Merge branch 'master' into csp-fix
This commit is contained in:
commit
ba4d8ceaf3
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -2,3 +2,6 @@
|
|||||||
path = ethcore/res/ethereum/tests
|
path = ethcore/res/ethereum/tests
|
||||||
url = https://github.com/ethereum/tests.git
|
url = https://github.com/ethereum/tests.git
|
||||||
branch = develop
|
branch = develop
|
||||||
|
[submodule "ethcore/res/wasm-tests"]
|
||||||
|
path = ethcore/res/wasm-tests
|
||||||
|
url = https://github.com/paritytech/wasm-tests
|
||||||
|
192
Cargo.lock
generated
192
Cargo.lock
generated
@ -57,6 +57,39 @@ dependencies = [
|
|||||||
"syntex_syntax 0.58.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syntex_syntax 0.58.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atty"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "backtrace"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"backtrace-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "backtrace-sys"
|
||||||
|
version = "0.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base-x"
|
name = "base-x"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@ -119,6 +152,11 @@ name = "bitflags"
|
|||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "0.9.1"
|
version = "0.9.1"
|
||||||
@ -144,6 +182,11 @@ dependencies = [
|
|||||||
"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)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@ -173,6 +216,21 @@ dependencies = [
|
|||||||
"multihash 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"multihash 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "2.24.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clippy"
|
name = "clippy"
|
||||||
version = "0.0.103"
|
version = "0.0.103"
|
||||||
@ -195,6 +253,14 @@ dependencies = [
|
|||||||
"unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "conv"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cookie"
|
name = "cookie"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@ -245,6 +311,11 @@ dependencies = [
|
|||||||
"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)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "custom_derive"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "daemonize"
|
name = "daemonize"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@ -253,6 +324,15 @@ 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)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dbghelp-sys"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deque"
|
name = "deque"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@ -305,6 +385,14 @@ dependencies = [
|
|||||||
"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)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "error-chain"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "eth-secp256k1"
|
name = "eth-secp256k1"
|
||||||
version = "0.5.6"
|
version = "0.5.6"
|
||||||
@ -376,6 +464,7 @@ dependencies = [
|
|||||||
"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)",
|
||||||
"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)",
|
||||||
|
"parity-wasm 0.12.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)",
|
||||||
"rlp 0.2.0",
|
"rlp 0.2.0",
|
||||||
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -385,6 +474,7 @@ dependencies = [
|
|||||||
"stats 0.1.0",
|
"stats 0.1.0",
|
||||||
"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)",
|
||||||
"transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"wasm-utils 0.1.0 (git+https://github.com/paritytech/wasm-utils)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1029,7 +1119,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-core"
|
name = "jsonrpc-core"
|
||||||
version = "7.0.0"
|
version = "7.0.0"
|
||||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#d12476f42ee672fa9d023f66fcfa5981d9aaba3a"
|
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#5e79be8a098cdda221713992f4a46b41a1d4d8f0"
|
||||||
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.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1041,7 +1131,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-http-server"
|
name = "jsonrpc-http-server"
|
||||||
version = "7.0.0"
|
version = "7.0.0"
|
||||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#d12476f42ee672fa9d023f66fcfa5981d9aaba3a"
|
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#5e79be8a098cdda221713992f4a46b41a1d4d8f0"
|
||||||
dependencies = [
|
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)",
|
||||||
@ -1054,7 +1144,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-ipc-server"
|
name = "jsonrpc-ipc-server"
|
||||||
version = "7.0.0"
|
version = "7.0.0"
|
||||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#d12476f42ee672fa9d023f66fcfa5981d9aaba3a"
|
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#5e79be8a098cdda221713992f4a46b41a1d4d8f0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bytes 0.4.4 (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)",
|
||||||
@ -1067,7 +1157,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-macros"
|
name = "jsonrpc-macros"
|
||||||
version = "7.0.0"
|
version = "7.0.0"
|
||||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#d12476f42ee672fa9d023f66fcfa5981d9aaba3a"
|
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#5e79be8a098cdda221713992f4a46b41a1d4d8f0"
|
||||||
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-pubsub 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
"jsonrpc-pubsub 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||||
@ -1077,7 +1167,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-minihttp-server"
|
name = "jsonrpc-minihttp-server"
|
||||||
version = "7.0.0"
|
version = "7.0.0"
|
||||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#d12476f42ee672fa9d023f66fcfa5981d9aaba3a"
|
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#5e79be8a098cdda221713992f4a46b41a1d4d8f0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bytes 0.4.4 (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)",
|
||||||
@ -1092,7 +1182,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-pubsub"
|
name = "jsonrpc-pubsub"
|
||||||
version = "7.0.0"
|
version = "7.0.0"
|
||||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#d12476f42ee672fa9d023f66fcfa5981d9aaba3a"
|
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#5e79be8a098cdda221713992f4a46b41a1d4d8f0"
|
||||||
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.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1102,8 +1192,9 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-server-utils"
|
name = "jsonrpc-server-utils"
|
||||||
version = "7.0.0"
|
version = "7.0.0"
|
||||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#d12476f42ee672fa9d023f66fcfa5981d9aaba3a"
|
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#5e79be8a098cdda221713992f4a46b41a1d4d8f0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bytes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"globset 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"globset 0.1.4 (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.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1114,7 +1205,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-tcp-server"
|
name = "jsonrpc-tcp-server"
|
||||||
version = "7.0.0"
|
version = "7.0.0"
|
||||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#d12476f42ee672fa9d023f66fcfa5981d9aaba3a"
|
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#5e79be8a098cdda221713992f4a46b41a1d4d8f0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bytes 0.4.4 (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)",
|
||||||
@ -1128,11 +1219,13 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-ws-server"
|
name = "jsonrpc-ws-server"
|
||||||
version = "7.0.0"
|
version = "7.0.0"
|
||||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#d12476f42ee672fa9d023f66fcfa5981d9aaba3a"
|
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#5e79be8a098cdda221713992f4a46b41a1d4d8f0"
|
||||||
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.7 (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)",
|
||||||
|
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ws 0.7.1 (git+https://github.com/tomusdrw/ws-rs)",
|
"ws 0.7.1 (git+https://github.com/tomusdrw/ws-rs)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1432,6 +1525,19 @@ name = "nom"
|
|||||||
version = "1.2.2"
|
version = "1.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ntp"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"error-chain 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num"
|
name = "num"
|
||||||
version = "0.1.32"
|
version = "0.1.32"
|
||||||
@ -1592,6 +1698,7 @@ dependencies = [
|
|||||||
"ethsync 1.7.0",
|
"ethsync 1.7.0",
|
||||||
"fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fdlimit 0.1.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)",
|
||||||
|
"futures-cpupool 0.1.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)",
|
||||||
"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.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1634,12 +1741,14 @@ 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)",
|
||||||
|
"futures-cpupool 0.1.2 (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)",
|
||||||
"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.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ntp 0.2.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-dapps-glue 1.7.0 (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",
|
||||||
@ -1743,6 +1852,7 @@ dependencies = [
|
|||||||
"ethsync 1.7.0",
|
"ethsync 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)",
|
||||||
|
"futures-cpupool 0.1.2 (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)",
|
||||||
"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)",
|
||||||
"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)",
|
||||||
@ -1848,6 +1958,16 @@ dependencies = [
|
|||||||
"target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parity-wasm"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder 1.0.0 (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)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parity-wordlist"
|
name = "parity-wordlist"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@ -2193,6 +2313,11 @@ dependencies = [
|
|||||||
"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)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-demangle"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hex"
|
name = "rustc-hex"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@ -2523,6 +2648,16 @@ dependencies = [
|
|||||||
"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)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "term_size"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termios"
|
name = "termios"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@ -2743,6 +2878,11 @@ name = "unicode-segmentation"
|
|||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
version = "0.0.4"
|
version = "0.0.4"
|
||||||
@ -2784,6 +2924,11 @@ name = "utf8-ranges"
|
|||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vec_map"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vecio"
|
name = "vecio"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -2807,6 +2952,18 @@ name = "void"
|
|||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/paritytech/wasm-utils#fee06b6d5826c2dc1fc1aa183b0c2c75e3e140c3"
|
||||||
|
dependencies = [
|
||||||
|
"clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"parity-wasm 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
@ -2882,6 +3039,9 @@ dependencies = [
|
|||||||
"checksum app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7d1c0d48a81bbb13043847f957971f4d87c81542d80ece5e84ba3cba4058fd4"
|
"checksum app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7d1c0d48a81bbb13043847f957971f4d87c81542d80ece5e84ba3cba4058fd4"
|
||||||
"checksum arrayvec 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d89f1b0e242270b5b797778af0c8d182a1a2ccac5d8d6fadf414223cc0fab096"
|
"checksum arrayvec 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d89f1b0e242270b5b797778af0c8d182a1a2ccac5d8d6fadf414223cc0fab096"
|
||||||
"checksum aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfdf7355d9db158df68f976ed030ab0f6578af811f5a7bb6dcf221ec24e0e0"
|
"checksum aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfdf7355d9db158df68f976ed030ab0f6578af811f5a7bb6dcf221ec24e0e0"
|
||||||
|
"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159"
|
||||||
|
"checksum backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "346d7644f0b5f9bc73082d3b2236b69a05fd35cce0cfa3724e184e6a5c9e2a2f"
|
||||||
|
"checksum backtrace-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3a0d842ea781ce92be2bf78a9b38883948542749640b8378b3b2f03d1fd9f1ff"
|
||||||
"checksum base-x 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f59103b47307f76e03bef1633aec7fa9e29bfb5aa6daf5a334f94233c71f6c1"
|
"checksum base-x 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f59103b47307f76e03bef1633aec7fa9e29bfb5aa6daf5a334f94233c71f6c1"
|
||||||
"checksum base32 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1b9605ba46d61df0410d8ac686b0007add8172eba90e8e909c347856fe794d8c"
|
"checksum base32 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1b9605ba46d61df0410d8ac686b0007add8172eba90e8e909c347856fe794d8c"
|
||||||
"checksum bigint 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0673c930652d3d4d6dcd5c45b5db4fa5f8f33994d7323618c43c083b223e8c"
|
"checksum bigint 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0673c930652d3d4d6dcd5c45b5db4fa5f8f33994d7323618c43c083b223e8c"
|
||||||
@ -2891,23 +3051,29 @@ dependencies = [
|
|||||||
"checksum bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5b97c2c8e8bbb4251754f559df8af22fb264853c7d009084a576cdf12565089d"
|
"checksum bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5b97c2c8e8bbb4251754f559df8af22fb264853c7d009084a576cdf12565089d"
|
||||||
"checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23"
|
"checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23"
|
||||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||||
|
"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4"
|
||||||
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
|
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
|
||||||
"checksum blastfig 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "09640e0509d97d5cdff03a9f5daf087a8e04c735c3b113a75139634a19cfc7b2"
|
"checksum blastfig 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "09640e0509d97d5cdff03a9f5daf087a8e04c735c3b113a75139634a19cfc7b2"
|
||||||
"checksum bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f421095d2a76fc24cd3fb3f912b90df06be7689912b1bdb423caefae59c258d"
|
"checksum bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f421095d2a76fc24cd3fb3f912b90df06be7689912b1bdb423caefae59c258d"
|
||||||
"checksum bn 0.4.4 (git+https://github.com/paritytech/bn)" = "<none>"
|
"checksum bn 0.4.4 (git+https://github.com/paritytech/bn)" = "<none>"
|
||||||
|
"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
|
||||||
"checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8"
|
"checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8"
|
||||||
"checksum bytes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8b24f16593f445422331a5eed46b72f7f171f910fead4f2ea8f17e727e9c5c14"
|
"checksum bytes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8b24f16593f445422331a5eed46b72f7f171f910fead4f2ea8f17e727e9c5c14"
|
||||||
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
|
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
|
||||||
"checksum cid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "34aa7da06f10541fbca6850719cdaa8fa03060a5d2fb33840f149cf8133a00c7"
|
"checksum cid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "34aa7da06f10541fbca6850719cdaa8fa03060a5d2fb33840f149cf8133a00c7"
|
||||||
|
"checksum clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b8f69e518f967224e628896b54e41ff6acfb4dcfefc5076325c36525dac900f"
|
||||||
"checksum clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "5b4fabf979ddf6419a313c1c0ada4a5b95cfd2049c56e8418d622d27b4b6ff32"
|
"checksum clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "5b4fabf979ddf6419a313c1c0ada4a5b95cfd2049c56e8418d622d27b4b6ff32"
|
||||||
"checksum clippy_lints 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "ce96ec05bfe018a0d5d43da115e54850ea2217981ff0f2e462780ab9d594651a"
|
"checksum clippy_lints 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "ce96ec05bfe018a0d5d43da115e54850ea2217981ff0f2e462780ab9d594651a"
|
||||||
|
"checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299"
|
||||||
"checksum cookie 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d53b80dde876f47f03cda35303e368a79b91c70b0d65ecba5fd5280944a08591"
|
"checksum cookie 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d53b80dde876f47f03cda35303e368a79b91c70b0d65ecba5fd5280944a08591"
|
||||||
"checksum core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "20a6d0448d3a99d977ae4a2aa5a98d886a923e863e81ad9ff814645b6feb3bbd"
|
"checksum core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "20a6d0448d3a99d977ae4a2aa5a98d886a923e863e81ad9ff814645b6feb3bbd"
|
||||||
"checksum core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "05eed248dc504a5391c63794fe4fb64f46f071280afaa1b73308f3c0ce4574c5"
|
"checksum core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "05eed248dc504a5391c63794fe4fb64f46f071280afaa1b73308f3c0ce4574c5"
|
||||||
"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97"
|
"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97"
|
||||||
"checksum crypt32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e34988f7e069e0b2f3bfc064295161e489b2d4e04a2e4248fb94360cdf00b4ec"
|
"checksum crypt32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e34988f7e069e0b2f3bfc064295161e489b2d4e04a2e4248fb94360cdf00b4ec"
|
||||||
"checksum ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)" = "<none>"
|
"checksum ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)" = "<none>"
|
||||||
|
"checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9"
|
||||||
"checksum daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "271ec51b7e0bee92f0d04601422c73eb76ececf197026711c97ad25038a010cf"
|
"checksum daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "271ec51b7e0bee92f0d04601422c73eb76ececf197026711c97ad25038a010cf"
|
||||||
|
"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
|
||||||
"checksum deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1614659040e711785ed8ea24219140654da1729f3ec8a47a9719d041112fe7bf"
|
"checksum deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1614659040e711785ed8ea24219140654da1729f3ec8a47a9719d041112fe7bf"
|
||||||
"checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8"
|
"checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8"
|
||||||
"checksum docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b5b93718f8b3e5544fcc914c43de828ca6c6ace23e0332c6080a2977b49787a"
|
"checksum docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b5b93718f8b3e5544fcc914c43de828ca6c6ace23e0332c6080a2977b49787a"
|
||||||
@ -2915,6 +3081,7 @@ dependencies = [
|
|||||||
"checksum either 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2b503c86dad62aaf414ecf2b8c527439abedb3f8d812537f0b12bfd6f32a91"
|
"checksum either 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2b503c86dad62aaf414ecf2b8c527439abedb3f8d812537f0b12bfd6f32a91"
|
||||||
"checksum elastic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "258ff6a9a94f648d0379dbd79110e057edbb53eb85cc237e33eadf8e5a30df85"
|
"checksum elastic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "258ff6a9a94f648d0379dbd79110e057edbb53eb85cc237e33eadf8e5a30df85"
|
||||||
"checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83"
|
"checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83"
|
||||||
|
"checksum error-chain 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5c82c815138e278b8dcdeffc49f27ea6ffb528403e9dea4194f2e3dd40b143"
|
||||||
"checksum eth-secp256k1 0.5.6 (git+https://github.com/paritytech/rust-secp256k1)" = "<none>"
|
"checksum eth-secp256k1 0.5.6 (git+https://github.com/paritytech/rust-secp256k1)" = "<none>"
|
||||||
"checksum ethabi 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c3d62319ee0f35abf20afe8859dd2668195912614346447bb2dee9fb8da7c62"
|
"checksum ethabi 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c3d62319ee0f35abf20afe8859dd2668195912614346447bb2dee9fb8da7c62"
|
||||||
"checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa"
|
"checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa"
|
||||||
@ -2985,6 +3152,7 @@ dependencies = [
|
|||||||
"checksum net2 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "bc01404e7568680f1259aa5729539f221cb1e6d047a0d9053cab4be8a73b5d67"
|
"checksum net2 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "bc01404e7568680f1259aa5729539f221cb1e6d047a0d9053cab4be8a73b5d67"
|
||||||
"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"
|
||||||
|
"checksum ntp 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d23f30ae7da76e2c6c2f5de53f298aa9a3911d3955ab2c349eb944caedceb088"
|
||||||
"checksum num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "c04bd954dbf96f76bab6e5bd6cef6f1ce1262d15268ce4f926d2b5b778fa7af2"
|
"checksum num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "c04bd954dbf96f76bab6e5bd6cef6f1ce1262d15268ce4f926d2b5b778fa7af2"
|
||||||
"checksum num-bigint 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "41655c8d667be847a0b72fe0888857a7b3f052f691cf40852be5fcf87b274a65"
|
"checksum num-bigint 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "41655c8d667be847a0b72fe0888857a7b3f052f691cf40852be5fcf87b274a65"
|
||||||
"checksum num-complex 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ccac67baf893ac97474f8d70eff7761dabb1f6c66e71f8f1c67a6859218db810"
|
"checksum num-complex 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ccac67baf893ac97474f8d70eff7761dabb1f6c66e71f8f1c67a6859218db810"
|
||||||
@ -3003,6 +3171,7 @@ dependencies = [
|
|||||||
"checksum parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1d06f6ee0fda786df3784a96ee3f0629f529b91cbfb7d142f6410e6bcd1ce2c"
|
"checksum parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1d06f6ee0fda786df3784a96ee3f0629f529b91cbfb7d142f6410e6bcd1ce2c"
|
||||||
"checksum parity-tokio-ipc 0.1.5 (git+https://github.com/nikvolf/parity-tokio-ipc)" = "<none>"
|
"checksum parity-tokio-ipc 0.1.5 (git+https://github.com/nikvolf/parity-tokio-ipc)" = "<none>"
|
||||||
"checksum parity-ui-precompiled 1.4.0 (git+https://github.com/paritytech/js-precompiled.git)" = "<none>"
|
"checksum parity-ui-precompiled 1.4.0 (git+https://github.com/paritytech/js-precompiled.git)" = "<none>"
|
||||||
|
"checksum parity-wasm 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "51104c8b8da5cd0ebe0ab765dfab37bc1927b4a01a3d870b0fe09d9ee65e35ea"
|
||||||
"checksum parity-wordlist 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "52142d717754f7ff7ef0fc8da1bdce4f302dd576fb9bf8b727d6a5fdef33348d"
|
"checksum parity-wordlist 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "52142d717754f7ff7ef0fc8da1bdce4f302dd576fb9bf8b727d6a5fdef33348d"
|
||||||
"checksum parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aebb68eebde2c99f89592d925288600fde220177e46b5c9a91ca218d245aeedf"
|
"checksum parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aebb68eebde2c99f89592d925288600fde220177e46b5c9a91ca218d245aeedf"
|
||||||
"checksum parking_lot_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb1b97670a2ffadce7c397fb80a3d687c4f3060140b885621ef1653d0e5d5068"
|
"checksum parking_lot_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb1b97670a2ffadce7c397fb80a3d687c4f3060140b885621ef1653d0e5d5068"
|
||||||
@ -3039,6 +3208,7 @@ dependencies = [
|
|||||||
"checksum rpassword 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5d3a99497c5c544e629cc8b359ae5ede321eba5fa8e5a8078f3ced727a976c3f"
|
"checksum rpassword 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5d3a99497c5c544e629cc8b359ae5ede321eba5fa8e5a8078f3ced727a976c3f"
|
||||||
"checksum rpassword 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab6e42be826e215f30ff830904f8f4a0933c6e2ae890e1af8b408f5bae60081e"
|
"checksum rpassword 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab6e42be826e215f30ff830904f8f4a0933c6e2ae890e1af8b408f5bae60081e"
|
||||||
"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
|
"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
|
||||||
|
"checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95"
|
||||||
"checksum rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0ceb8ce7a5e520de349e1fa172baeba4a9e8d5ef06c47471863530bc4972ee1e"
|
"checksum rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0ceb8ce7a5e520de349e1fa172baeba4a9e8d5ef06c47471863530bc4972ee1e"
|
||||||
"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
|
"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
|
||||||
"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
|
"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
|
||||||
@ -3080,6 +3250,7 @@ dependencies = [
|
|||||||
"checksum target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c63f48baada5c52e65a29eef93ab4f8982681b67f9e8d29c7b05abcfec2b9ffe"
|
"checksum target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c63f48baada5c52e65a29eef93ab4f8982681b67f9e8d29c7b05abcfec2b9ffe"
|
||||||
"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
|
"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
|
||||||
"checksum term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d168af3930b369cfe245132550579d47dfd873d69470755a19c2c6568dbbd989"
|
"checksum term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d168af3930b369cfe245132550579d47dfd873d69470755a19c2c6568dbbd989"
|
||||||
|
"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
|
||||||
"checksum termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d9cf598a6d7ce700a4e6a9199da127e6819a61e64b68609683cc9a01b5683a"
|
"checksum termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d9cf598a6d7ce700a4e6a9199da127e6819a61e64b68609683cc9a01b5683a"
|
||||||
"checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a"
|
"checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a"
|
||||||
"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"
|
||||||
@ -3103,15 +3274,18 @@ dependencies = [
|
|||||||
"checksum unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c1f7ceb96afdfeedee42bade65a0d585a6a0106f681b6749c8ff4daa8df30b3f"
|
"checksum unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c1f7ceb96afdfeedee42bade65a0d585a6a0106f681b6749c8ff4daa8df30b3f"
|
||||||
"checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172"
|
"checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172"
|
||||||
"checksum unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18127285758f0e2c6cf325bb3f3d138a12fee27de4f23e146cd6a179f26c2cf3"
|
"checksum unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18127285758f0e2c6cf325bb3f3d138a12fee27de4f23e146cd6a179f26c2cf3"
|
||||||
|
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
|
||||||
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
|
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
|
||||||
"checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91"
|
"checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91"
|
||||||
"checksum untrusted 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b65243989ef6aacd9c0d6bd2b822765c3361d8ed352185a6f3a41f3a718c673"
|
"checksum untrusted 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b65243989ef6aacd9c0d6bd2b822765c3361d8ed352185a6f3a41f3a718c673"
|
||||||
"checksum url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afe9ec54bc4db14bc8744b7fed060d785ac756791450959b2248443319d5b119"
|
"checksum url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afe9ec54bc4db14bc8744b7fed060d785ac756791450959b2248443319d5b119"
|
||||||
"checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47"
|
"checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47"
|
||||||
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
|
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
|
||||||
|
"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
|
||||||
"checksum vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0795a11576d29ae80525a3fda315bf7b534f8feb9d34101e5fe63fb95bb2fd24"
|
"checksum vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0795a11576d29ae80525a3fda315bf7b534f8feb9d34101e5fe63fb95bb2fd24"
|
||||||
"checksum vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56b639f935488eb40f06d17c3e3bcc3054f6f75d264e187b1107c8d1cba8d31c"
|
"checksum vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56b639f935488eb40f06d17c3e3bcc3054f6f75d264e187b1107c8d1cba8d31c"
|
||||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||||
|
"checksum wasm-utils 0.1.0 (git+https://github.com/paritytech/wasm-utils)" = "<none>"
|
||||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||||
"checksum ws 0.7.1 (git+https://github.com/tomusdrw/ws-rs)" = "<none>"
|
"checksum ws 0.7.1 (git+https://github.com/tomusdrw/ws-rs)" = "<none>"
|
||||||
|
@ -25,6 +25,7 @@ serde_json = "1.0"
|
|||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
app_dirs = "1.1.1"
|
app_dirs = "1.1.1"
|
||||||
futures = "0.1"
|
futures = "0.1"
|
||||||
|
futures-cpupool = "0.1"
|
||||||
fdlimit = "0.1"
|
fdlimit = "0.1"
|
||||||
ws2_32-sys = "0.2"
|
ws2_32-sys = "0.2"
|
||||||
ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" }
|
ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" }
|
||||||
|
@ -11,11 +11,13 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
|||||||
base32 = "0.3"
|
base32 = "0.3"
|
||||||
env_logger = "0.4"
|
env_logger = "0.4"
|
||||||
futures = "0.1"
|
futures = "0.1"
|
||||||
|
futures-cpupool = "0.1"
|
||||||
linked-hash-map = "0.3"
|
linked-hash-map = "0.3"
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
parity-dapps-glue = "1.7"
|
parity-dapps-glue = "1.7"
|
||||||
mime = "0.2"
|
mime = "0.2"
|
||||||
mime_guess = "1.6.1"
|
mime_guess = "1.6.1"
|
||||||
|
ntp = "0.2.0"
|
||||||
rand = "0.3"
|
rand = "0.3"
|
||||||
rustc-hex = "1.0"
|
rustc-hex = "1.0"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
|
@ -18,23 +18,36 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use hyper::{server, net, Decoder, Encoder, Next, Control};
|
use hyper::{server, net, Decoder, Encoder, Next, Control};
|
||||||
use hyper::method::Method;
|
use hyper::method::Method;
|
||||||
|
use hyper::status::StatusCode;
|
||||||
|
|
||||||
use api::types::ApiError;
|
use api::{response, types};
|
||||||
use api::response;
|
use api::time::TimeChecker;
|
||||||
use apps::fetcher::Fetcher;
|
use apps::fetcher::Fetcher;
|
||||||
|
use handlers::{self, extract_url};
|
||||||
use handlers::extract_url;
|
|
||||||
use endpoint::{Endpoint, Handler, EndpointPath};
|
use endpoint::{Endpoint, Handler, EndpointPath};
|
||||||
|
use parity_reactor::Remote;
|
||||||
|
use {SyncStatus};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct RestApi {
|
pub struct RestApi {
|
||||||
fetcher: Arc<Fetcher>,
|
fetcher: Arc<Fetcher>,
|
||||||
|
sync_status: Arc<SyncStatus>,
|
||||||
|
time: TimeChecker,
|
||||||
|
remote: Remote,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RestApi {
|
impl RestApi {
|
||||||
pub fn new(fetcher: Arc<Fetcher>) -> Box<Endpoint> {
|
pub fn new(
|
||||||
|
fetcher: Arc<Fetcher>,
|
||||||
|
sync_status: Arc<SyncStatus>,
|
||||||
|
time: TimeChecker,
|
||||||
|
remote: Remote,
|
||||||
|
) -> Box<Endpoint> {
|
||||||
Box::new(RestApi {
|
Box::new(RestApi {
|
||||||
fetcher: fetcher,
|
fetcher,
|
||||||
|
sync_status,
|
||||||
|
time,
|
||||||
|
remote,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,11 +71,11 @@ impl RestApiRouter {
|
|||||||
path: Some(path),
|
path: Some(path),
|
||||||
control: Some(control),
|
control: Some(control),
|
||||||
api: api,
|
api: api,
|
||||||
handler: response::as_json_error(&ApiError {
|
handler: Box::new(response::as_json_error(StatusCode::NotFound, &types::ApiError {
|
||||||
code: "404".into(),
|
code: "404".into(),
|
||||||
title: "Not Found".into(),
|
title: "Not Found".into(),
|
||||||
detail: "Resource you requested has not been found.".into(),
|
detail: "Resource you requested has not been found.".into(),
|
||||||
}),
|
})),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,6 +88,78 @@ impl RestApiRouter {
|
|||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn health(&self, control: Control) -> Box<Handler> {
|
||||||
|
use self::types::{HealthInfo, HealthStatus, Health};
|
||||||
|
|
||||||
|
trace!(target: "dapps", "Checking node health.");
|
||||||
|
// Check timediff
|
||||||
|
let sync_status = self.api.sync_status.clone();
|
||||||
|
let map = move |time| {
|
||||||
|
// Check peers
|
||||||
|
let peers = {
|
||||||
|
let (connected, max) = sync_status.peers();
|
||||||
|
let (status, message) = match connected {
|
||||||
|
0 => {
|
||||||
|
(HealthStatus::Bad, "You are not connected to any peers. There is most likely some network issue. Fix connectivity.".into())
|
||||||
|
},
|
||||||
|
1 => (HealthStatus::NeedsAttention, "You are connected to only one peer. Your node might not be reliable. Check your network connection.".into()),
|
||||||
|
_ => (HealthStatus::Ok, "".into()),
|
||||||
|
};
|
||||||
|
HealthInfo { status, message, details: (connected, max) }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check sync
|
||||||
|
let sync = {
|
||||||
|
let is_syncing = sync_status.is_major_importing();
|
||||||
|
let (status, message) = if is_syncing {
|
||||||
|
(HealthStatus::NeedsAttention, "Your node is still syncing, the values you see might be outdated. Wait until it's fully synced.".into())
|
||||||
|
} else {
|
||||||
|
(HealthStatus::Ok, "".into())
|
||||||
|
};
|
||||||
|
HealthInfo { status, message, details: is_syncing }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check time
|
||||||
|
let time = {
|
||||||
|
const MAX_DRIFT: i64 = 500;
|
||||||
|
let (status, message, details) = match time {
|
||||||
|
Ok(Ok(diff)) if diff < MAX_DRIFT && diff > -MAX_DRIFT => {
|
||||||
|
(HealthStatus::Ok, "".into(), diff)
|
||||||
|
},
|
||||||
|
Ok(Ok(diff)) => {
|
||||||
|
(HealthStatus::Bad, format!(
|
||||||
|
"Your clock is not in sync. Detected difference is too big for the protocol to work: {}ms. Synchronize your clock.",
|
||||||
|
diff,
|
||||||
|
), diff)
|
||||||
|
},
|
||||||
|
Ok(Err(err)) => {
|
||||||
|
(HealthStatus::NeedsAttention, format!(
|
||||||
|
"Unable to reach time API: {}. Make sure that your clock is synchronized.",
|
||||||
|
err,
|
||||||
|
), 0)
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
(HealthStatus::NeedsAttention, "Time API request timed out. Make sure that the clock is synchronized.".into(), 0)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
HealthInfo { status, message, details, }
|
||||||
|
};
|
||||||
|
|
||||||
|
let status = if [&peers.status, &sync.status, &time.status].iter().any(|x| *x != &HealthStatus::Ok) {
|
||||||
|
StatusCode::PreconditionFailed // HTTP 412
|
||||||
|
} else {
|
||||||
|
StatusCode::Ok // HTTP 200
|
||||||
|
};
|
||||||
|
|
||||||
|
response::as_json(status, &Health { peers, sync, time })
|
||||||
|
};
|
||||||
|
|
||||||
|
let time = self.api.time.time_drift();
|
||||||
|
let remote = self.api.remote.clone();
|
||||||
|
Box::new(handlers::AsyncHandler::new(time, map, remote, control))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl server::Handler<net::HttpStream> for RestApiRouter {
|
impl server::Handler<net::HttpStream> for RestApiRouter {
|
||||||
@ -103,6 +188,7 @@ impl server::Handler<net::HttpStream> for RestApiRouter {
|
|||||||
|
|
||||||
let handler = endpoint.and_then(|v| match v {
|
let handler = endpoint.and_then(|v| match v {
|
||||||
"ping" => Some(response::ping()),
|
"ping" => Some(response::ping()),
|
||||||
|
"health" => Some(self.health(control)),
|
||||||
"content" => self.resolve_content(hash, path, control),
|
"content" => self.resolve_content(hash, path, control),
|
||||||
_ => None
|
_ => None
|
||||||
});
|
});
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
mod api;
|
mod api;
|
||||||
mod response;
|
mod response;
|
||||||
|
mod time;
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
pub use self::api::RestApi;
|
pub use self::api::RestApi;
|
||||||
|
pub use self::time::TimeChecker;
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
use hyper::status::StatusCode;
|
||||||
|
|
||||||
use endpoint::Handler;
|
use endpoint::Handler;
|
||||||
use handlers::{ContentHandler, EchoHandler};
|
use handlers::{ContentHandler, EchoHandler};
|
||||||
|
|
||||||
@ -23,10 +25,16 @@ pub fn empty() -> Box<Handler> {
|
|||||||
Box::new(ContentHandler::ok("".into(), mime!(Text/Plain)))
|
Box::new(ContentHandler::ok("".into(), mime!(Text/Plain)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_json_error<T: Serialize>(val: &T) -> Box<Handler> {
|
pub fn as_json<T: Serialize>(status: StatusCode, val: &T) -> ContentHandler {
|
||||||
let json = serde_json::to_string(val)
|
let json = serde_json::to_string(val)
|
||||||
.expect("serialization to string is infallible; qed");
|
.expect("serialization to string is infallible; qed");
|
||||||
Box::new(ContentHandler::not_found(json, mime!(Application/Json)))
|
ContentHandler::new(status, json, mime!(Application/Json))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_json_error<T: Serialize>(status: StatusCode, val: &T) -> ContentHandler {
|
||||||
|
let json = serde_json::to_string(val)
|
||||||
|
.expect("serialization to string is infallible; qed");
|
||||||
|
ContentHandler::new(status, json, mime!(Application/Json))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ping() -> Box<Handler> {
|
pub fn ping() -> Box<Handler> {
|
||||||
|
264
dapps/src/api/time.rs
Normal file
264
dapps/src/api/time.rs
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
//! Periodically checks node's time drift using [SNTP](https://tools.ietf.org/html/rfc1769).
|
||||||
|
//!
|
||||||
|
//! An NTP packet is sent to the server with a local timestamp, the server then completes the packet, yielding the
|
||||||
|
//! following timestamps:
|
||||||
|
//!
|
||||||
|
//! Timestamp Name ID When Generated
|
||||||
|
//! ------------------------------------------------------------
|
||||||
|
//! Originate Timestamp T1 time request sent by client
|
||||||
|
//! Receive Timestamp T2 time request received at server
|
||||||
|
//! Transmit Timestamp T3 time reply sent by server
|
||||||
|
//! Destination Timestamp T4 time reply received at client
|
||||||
|
//!
|
||||||
|
//! The drift is defined as:
|
||||||
|
//!
|
||||||
|
//! drift = ((T2 - T1) + (T3 - T4)) / 2.
|
||||||
|
//!
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
use std::{fmt, mem, time};
|
||||||
|
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use futures::{self, Future, BoxFuture};
|
||||||
|
use futures_cpupool::CpuPool;
|
||||||
|
use ntp;
|
||||||
|
use time::{Duration, Timespec};
|
||||||
|
use util::{Arc, RwLock};
|
||||||
|
|
||||||
|
/// Time checker error.
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum Error {
|
||||||
|
/// There was an error when trying to reach the NTP server.
|
||||||
|
Ntp(String),
|
||||||
|
/// IO error when reading NTP response.
|
||||||
|
Io(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
use self::Error::*;
|
||||||
|
|
||||||
|
match *self {
|
||||||
|
Ntp(ref err) => write!(fmt, "NTP error: {}", err),
|
||||||
|
Io(ref err) => write!(fmt, "Connection Error: {}", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for Error {
|
||||||
|
fn from(err: io::Error) -> Self { Error::Io(format!("{}", err)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ntp::errors::Error> for Error {
|
||||||
|
fn from(err: ntp::errors::Error) -> Self { Error::Ntp(format!("{}", err)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// NTP time drift checker.
|
||||||
|
pub trait Ntp {
|
||||||
|
/// Returns the current time drift.
|
||||||
|
fn drift(&self) -> BoxFuture<Duration, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// NTP client using the SNTP algorithm for calculating drift.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SimpleNtp {
|
||||||
|
address: Arc<String>,
|
||||||
|
pool: CpuPool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for SimpleNtp {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "Ntp {{ address: {} }}", self.address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimpleNtp {
|
||||||
|
fn new(address: &str, pool: CpuPool) -> SimpleNtp {
|
||||||
|
SimpleNtp {
|
||||||
|
address: Arc::new(address.to_owned()),
|
||||||
|
pool: pool,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ntp for SimpleNtp {
|
||||||
|
fn drift(&self) -> BoxFuture<Duration, Error> {
|
||||||
|
let address = self.address.clone();
|
||||||
|
self.pool.spawn_fn(move || {
|
||||||
|
let packet = ntp::request(&*address)?;
|
||||||
|
let dest_time = ::time::now_utc().to_timespec();
|
||||||
|
let orig_time = Timespec::from(packet.orig_time);
|
||||||
|
let recv_time = Timespec::from(packet.recv_time);
|
||||||
|
let transmit_time = Timespec::from(packet.transmit_time);
|
||||||
|
|
||||||
|
let drift = ((recv_time - orig_time) + (transmit_time - dest_time)) / 2;
|
||||||
|
|
||||||
|
Ok(drift)
|
||||||
|
}).boxed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_RESULTS: usize = 4;
|
||||||
|
const UPDATE_TIMEOUT_OK_SECS: u64 = 30;
|
||||||
|
const UPDATE_TIMEOUT_ERR_SECS: u64 = 2;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
/// A time checker.
|
||||||
|
pub struct TimeChecker<N: Ntp = SimpleNtp> {
|
||||||
|
ntp: N,
|
||||||
|
last_result: Arc<RwLock<(time::Instant, VecDeque<Result<i64, Error>>)>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TimeChecker<SimpleNtp> {
|
||||||
|
/// Creates new time checker given the NTP server address.
|
||||||
|
pub fn new(ntp_address: String, pool: CpuPool) -> Self {
|
||||||
|
let last_result = Arc::new(RwLock::new(
|
||||||
|
// Assume everything is ok at the very beginning.
|
||||||
|
(time::Instant::now(), vec![Ok(0)].into())
|
||||||
|
));
|
||||||
|
|
||||||
|
let ntp = SimpleNtp::new(&ntp_address, pool);
|
||||||
|
|
||||||
|
TimeChecker {
|
||||||
|
ntp,
|
||||||
|
last_result,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Ntp> TimeChecker<N> {
|
||||||
|
/// Updates the time
|
||||||
|
pub fn update(&self) -> BoxFuture<i64, Error> {
|
||||||
|
let last_result = self.last_result.clone();
|
||||||
|
self.ntp.drift().then(move |res| {
|
||||||
|
let mut results = mem::replace(&mut last_result.write().1, VecDeque::new());
|
||||||
|
let valid_till = time::Instant::now() + time::Duration::from_secs(
|
||||||
|
if res.is_ok() && results.len() == MAX_RESULTS {
|
||||||
|
UPDATE_TIMEOUT_OK_SECS
|
||||||
|
} else {
|
||||||
|
UPDATE_TIMEOUT_ERR_SECS
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Push the result.
|
||||||
|
results.push_back(res.map(|d| d.num_milliseconds()));
|
||||||
|
while results.len() > MAX_RESULTS {
|
||||||
|
results.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select a response and update last result.
|
||||||
|
let res = select_result(results.iter());
|
||||||
|
*last_result.write() = (valid_till, results);
|
||||||
|
res
|
||||||
|
}).boxed()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a current time drift or error if last request to NTP server failed.
|
||||||
|
pub fn time_drift(&self) -> BoxFuture<i64, Error> {
|
||||||
|
// return cached result
|
||||||
|
{
|
||||||
|
let res = self.last_result.read();
|
||||||
|
if res.0 > time::Instant::now() {
|
||||||
|
return futures::done(select_result(res.1.iter())).boxed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// or update and return result
|
||||||
|
self.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select_result<'a, T: Iterator<Item=&'a Result<i64, Error>>>(results: T) -> Result<i64, Error> {
|
||||||
|
let mut min = None;
|
||||||
|
for res in results {
|
||||||
|
min = Some(match (min.take(), res) {
|
||||||
|
(Some(Ok(min)), &Ok(ref new)) => Ok(::std::cmp::min(min, *new)),
|
||||||
|
(Some(Ok(old)), &Err(_)) => Ok(old),
|
||||||
|
(_, ref new) => (*new).clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
min.unwrap_or_else(|| Err(Error::Ntp("NTP server unavailable.".into())))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::cell::{Cell, RefCell};
|
||||||
|
use std::time::Instant;
|
||||||
|
use time::Duration;
|
||||||
|
use futures::{self, BoxFuture, Future};
|
||||||
|
use super::{Ntp, TimeChecker, Error};
|
||||||
|
use util::RwLock;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct FakeNtp(RefCell<Vec<Duration>>, Cell<u64>);
|
||||||
|
impl FakeNtp {
|
||||||
|
fn new() -> FakeNtp {
|
||||||
|
FakeNtp(
|
||||||
|
RefCell::new(vec![Duration::milliseconds(150)]),
|
||||||
|
Cell::new(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ntp for FakeNtp {
|
||||||
|
fn drift(&self) -> BoxFuture<Duration, Error> {
|
||||||
|
self.1.set(self.1.get() + 1);
|
||||||
|
futures::future::ok(self.0.borrow_mut().pop().expect("Unexpected call to drift().")).boxed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn time_checker() -> TimeChecker<FakeNtp> {
|
||||||
|
let last_result = Arc::new(RwLock::new(
|
||||||
|
(Instant::now(), vec![Err(Error::Ntp("NTP server unavailable.".into()))].into())
|
||||||
|
));
|
||||||
|
|
||||||
|
TimeChecker {
|
||||||
|
ntp: FakeNtp::new(),
|
||||||
|
last_result: last_result,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_fetch_time_on_start() {
|
||||||
|
// given
|
||||||
|
let time = time_checker();
|
||||||
|
|
||||||
|
// when
|
||||||
|
let diff = time.time_drift().wait().unwrap();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert_eq!(diff, 150);
|
||||||
|
assert_eq!(time.ntp.1.get(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_not_fetch_twice_if_timeout_has_not_passed() {
|
||||||
|
// given
|
||||||
|
let time = time_checker();
|
||||||
|
|
||||||
|
// when
|
||||||
|
let diff1 = time.time_drift().wait().unwrap();
|
||||||
|
let diff2 = time.time_drift().wait().unwrap();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert_eq!(diff1, 150);
|
||||||
|
assert_eq!(diff2, 150);
|
||||||
|
assert_eq!(time.ntp.1.get(), 1);
|
||||||
|
}
|
||||||
|
}
|
@ -14,11 +14,54 @@
|
|||||||
// 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/>.
|
||||||
|
|
||||||
|
/// A structure representing any error in REST API.
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct ApiError {
|
pub struct ApiError {
|
||||||
|
/// Error code.
|
||||||
pub code: String,
|
pub code: String,
|
||||||
|
/// Human-readable error summary.
|
||||||
pub title: String,
|
pub title: String,
|
||||||
|
/// More technical error details.
|
||||||
pub detail: String,
|
pub detail: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Health API endpoint status.
|
||||||
|
#[derive(Debug, PartialEq, Serialize)]
|
||||||
|
pub enum HealthStatus {
|
||||||
|
/// Everything's OK.
|
||||||
|
#[serde(rename = "ok")]
|
||||||
|
Ok,
|
||||||
|
/// Node health need attention
|
||||||
|
/// (the issue is not critical, but may need investigation)
|
||||||
|
#[serde(rename = "needsAttention")]
|
||||||
|
NeedsAttention,
|
||||||
|
/// There is something bad detected with the node.
|
||||||
|
#[serde(rename = "bad")]
|
||||||
|
Bad
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a single check in node health.
|
||||||
|
/// Cointains the status of that check and apropriate message and details.
|
||||||
|
#[derive(Debug, PartialEq, Serialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct HealthInfo<T> {
|
||||||
|
/// Check status.
|
||||||
|
pub status: HealthStatus,
|
||||||
|
/// Human-readable message.
|
||||||
|
pub message: String,
|
||||||
|
/// Technical details of the check.
|
||||||
|
pub details: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Node Health status.
|
||||||
|
#[derive(Debug, PartialEq, Serialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct Health {
|
||||||
|
/// Status of peers.
|
||||||
|
pub peers: HealthInfo<(usize, usize)>,
|
||||||
|
/// Sync status.
|
||||||
|
pub sync: HealthInfo<bool>,
|
||||||
|
/// Time diff info.
|
||||||
|
pub time: HealthInfo<i64>,
|
||||||
|
}
|
||||||
|
@ -48,7 +48,7 @@ pub trait Fetcher: Send + Sync + 'static {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct ContentFetcher<F: Fetch = FetchClient, R: URLHint + 'static = URLHintContract> {
|
pub struct ContentFetcher<F: Fetch = FetchClient, R: URLHint + 'static = URLHintContract> {
|
||||||
dapps_path: PathBuf,
|
cache_path: PathBuf,
|
||||||
resolver: R,
|
resolver: R,
|
||||||
cache: Arc<Mutex<ContentCache>>,
|
cache: Arc<Mutex<ContentCache>>,
|
||||||
sync: Arc<SyncStatus>,
|
sync: Arc<SyncStatus>,
|
||||||
@ -61,7 +61,7 @@ pub struct ContentFetcher<F: Fetch = FetchClient, R: URLHint + 'static = URLHint
|
|||||||
impl<R: URLHint + 'static, F: Fetch> 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.cache_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,11 +73,11 @@ impl<R: URLHint + 'static, F: Fetch> ContentFetcher<F, R> {
|
|||||||
remote: Remote,
|
remote: Remote,
|
||||||
fetch: F,
|
fetch: F,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut dapps_path = env::temp_dir();
|
let mut cache_path = env::temp_dir();
|
||||||
dapps_path.push(random_filename());
|
cache_path.push(random_filename());
|
||||||
|
|
||||||
ContentFetcher {
|
ContentFetcher {
|
||||||
dapps_path: dapps_path,
|
cache_path: cache_path,
|
||||||
resolver: resolver,
|
resolver: resolver,
|
||||||
sync: sync_status,
|
sync: sync_status,
|
||||||
cache: Arc::new(Mutex::new(ContentCache::default())),
|
cache: Arc::new(Mutex::new(ContentCache::default())),
|
||||||
@ -200,7 +200,7 @@ impl<R: URLHint + 'static, F: Fetch> Fetcher for ContentFetcher<F, R> {
|
|||||||
control,
|
control,
|
||||||
installers::Dapp::new(
|
installers::Dapp::new(
|
||||||
content_id.clone(),
|
content_id.clone(),
|
||||||
self.dapps_path.clone(),
|
self.cache_path.clone(),
|
||||||
Box::new(on_done),
|
Box::new(on_done),
|
||||||
self.embeddable_on.clone(),
|
self.embeddable_on.clone(),
|
||||||
),
|
),
|
||||||
@ -219,7 +219,7 @@ impl<R: URLHint + 'static, F: Fetch> Fetcher for ContentFetcher<F, R> {
|
|||||||
installers::Content::new(
|
installers::Content::new(
|
||||||
content_id.clone(),
|
content_id.clone(),
|
||||||
content.mime,
|
content.mime,
|
||||||
self.dapps_path.clone(),
|
self.cache_path.clone(),
|
||||||
Box::new(on_done),
|
Box::new(on_done),
|
||||||
),
|
),
|
||||||
self.embeddable_on.clone(),
|
self.embeddable_on.clone(),
|
||||||
@ -271,6 +271,7 @@ mod tests {
|
|||||||
use endpoint::EndpointInfo;
|
use endpoint::EndpointInfo;
|
||||||
use page::LocalPageEndpoint;
|
use page::LocalPageEndpoint;
|
||||||
use super::{ContentFetcher, Fetcher};
|
use super::{ContentFetcher, Fetcher};
|
||||||
|
use {SyncStatus};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct FakeResolver;
|
struct FakeResolver;
|
||||||
@ -280,11 +281,17 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct FakeSync(bool);
|
||||||
|
impl SyncStatus for FakeSync {
|
||||||
|
fn is_major_importing(&self) -> bool { self.0 }
|
||||||
|
fn peers(&self) -> (usize, usize) { (0, 5) }
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_true_if_contains_the_app() {
|
fn should_true_if_contains_the_app() {
|
||||||
// given
|
// given
|
||||||
let path = env::temp_dir();
|
let path = env::temp_dir();
|
||||||
let fetcher = ContentFetcher::new(FakeResolver, Arc::new(|| false), Remote::new_sync(), Client::new().unwrap())
|
let fetcher = ContentFetcher::new(FakeResolver, Arc::new(FakeSync(false)), Remote::new_sync(), Client::new().unwrap())
|
||||||
.allow_dapps(true);
|
.allow_dapps(true);
|
||||||
let handler = LocalPageEndpoint::new(path, EndpointInfo {
|
let handler = LocalPageEndpoint::new(path, EndpointInfo {
|
||||||
name: "fake".into(),
|
name: "fake".into(),
|
||||||
|
@ -26,7 +26,7 @@ use fetch::Fetch;
|
|||||||
use parity_dapps::WebApp;
|
use parity_dapps::WebApp;
|
||||||
use parity_reactor::Remote;
|
use parity_reactor::Remote;
|
||||||
use parity_ui;
|
use parity_ui;
|
||||||
use {WebProxyTokens, ParentFrameSettings, as_embeddable};
|
use {WebProxyTokens, ParentFrameSettings};
|
||||||
|
|
||||||
mod app;
|
mod app;
|
||||||
mod cache;
|
mod cache;
|
||||||
@ -52,20 +52,19 @@ pub fn ui() -> Box<Endpoint> {
|
|||||||
Box::new(PageEndpoint::with_fallback_to_index(parity_ui::App::default()))
|
Box::new(PageEndpoint::with_fallback_to_index(parity_ui::App::default()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ui_redirection(ui_address: Option<(String, u16)>, dapps_domain: String) -> Box<Endpoint> {
|
pub fn ui_redirection(embeddable: Option<ParentFrameSettings>) -> Box<Endpoint> {
|
||||||
Box::new(ui::Redirection::new(as_embeddable(ui_address, dapps_domain)))
|
Box::new(ui::Redirection::new(embeddable))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_endpoints<F: Fetch>(
|
pub fn all_endpoints<F: Fetch>(
|
||||||
dapps_path: PathBuf,
|
dapps_path: PathBuf,
|
||||||
extra_dapps: Vec<PathBuf>,
|
extra_dapps: Vec<PathBuf>,
|
||||||
dapps_domain: String,
|
dapps_domain: &str,
|
||||||
ui_address: Option<(String, u16)>,
|
embeddable: Option<ParentFrameSettings>,
|
||||||
web_proxy_tokens: Arc<WebProxyTokens>,
|
web_proxy_tokens: Arc<WebProxyTokens>,
|
||||||
remote: Remote,
|
remote: Remote,
|
||||||
fetch: F,
|
fetch: F,
|
||||||
) -> Endpoints {
|
) -> Endpoints {
|
||||||
let embeddable = as_embeddable(ui_address.clone(), dapps_domain.clone());
|
|
||||||
// fetch fs dapps at first to avoid overwriting builtins
|
// fetch fs dapps at first to avoid overwriting builtins
|
||||||
let mut pages = fs::local_endpoints(dapps_path, embeddable.clone());
|
let mut pages = fs::local_endpoints(dapps_path, embeddable.clone());
|
||||||
for path in extra_dapps {
|
for path in extra_dapps {
|
||||||
@ -78,7 +77,7 @@ pub fn all_endpoints<F: Fetch>(
|
|||||||
|
|
||||||
// NOTE [ToDr] Dapps will be currently embeded on 8180
|
// NOTE [ToDr] Dapps will be currently embeded on 8180
|
||||||
insert::<parity_ui::App>(&mut pages, "ui", Embeddable::Yes(embeddable.clone()));
|
insert::<parity_ui::App>(&mut pages, "ui", Embeddable::Yes(embeddable.clone()));
|
||||||
pages.insert("proxy".into(), ProxyPac::boxed(ui_address.clone(), dapps_domain));
|
pages.insert("proxy".into(), ProxyPac::boxed(embeddable.clone(), dapps_domain.to_owned()));
|
||||||
pages.insert(WEB_PATH.into(), Web::boxed(embeddable.clone(), web_proxy_tokens.clone(), remote.clone(), fetch.clone()));
|
pages.insert(WEB_PATH.into(), Web::boxed(embeddable.clone(), web_proxy_tokens.clone(), remote.clone(), fetch.clone()));
|
||||||
|
|
||||||
Arc::new(pages)
|
Arc::new(pages)
|
||||||
|
112
dapps/src/handlers/async.rs
Normal file
112
dapps/src/handlers/async.rs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
//! Async Content Handler
|
||||||
|
//! Temporary solution until we switch to future-based server.
|
||||||
|
//! Wraps a future and converts it to hyper::server::Handler;
|
||||||
|
|
||||||
|
use std::{mem, time};
|
||||||
|
use std::sync::mpsc;
|
||||||
|
use futures::Future;
|
||||||
|
use hyper::{server, Decoder, Encoder, Next, Control};
|
||||||
|
use hyper::net::HttpStream;
|
||||||
|
|
||||||
|
use handlers::ContentHandler;
|
||||||
|
use parity_reactor::Remote;
|
||||||
|
|
||||||
|
const TIMEOUT_SECS: u64 = 15;
|
||||||
|
|
||||||
|
enum State<F, T, M> {
|
||||||
|
Initial(F, M, Remote, Control),
|
||||||
|
Waiting(mpsc::Receiver<Result<T, ()>>, M),
|
||||||
|
Done(ContentHandler),
|
||||||
|
Invalid,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AsyncHandler<F, T, M> {
|
||||||
|
state: State<F, T, M>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F, T, M> AsyncHandler<F, T, M> {
|
||||||
|
pub fn new(future: F, map: M, remote: Remote, control: Control) -> Self {
|
||||||
|
AsyncHandler {
|
||||||
|
state: State::Initial(future, map, remote, control),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F, T, E, M> server::Handler<HttpStream> for AsyncHandler<F, Result<T, E>, M> where
|
||||||
|
F: Future<Item=T, Error=E> + Send + 'static,
|
||||||
|
M: FnOnce(Result<Result<T, E>, ()>) -> ContentHandler,
|
||||||
|
T: Send + 'static,
|
||||||
|
E: Send + 'static,
|
||||||
|
{
|
||||||
|
fn on_request(&mut self, _request: server::Request<HttpStream>) -> Next {
|
||||||
|
if let State::Initial(future, map, remote, control) = mem::replace(&mut self.state, State::Invalid) {
|
||||||
|
let (tx, rx) = mpsc::sync_channel(1);
|
||||||
|
let control2 = control.clone();
|
||||||
|
let tx2 = tx.clone();
|
||||||
|
remote.spawn_with_timeout(move || future.then(move |result| {
|
||||||
|
// Send a result (ignore errors if the connection was dropped)
|
||||||
|
let _ = tx.send(Ok(result));
|
||||||
|
// Resume handler
|
||||||
|
let _ = control.ready(Next::read());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}), time::Duration::from_secs(TIMEOUT_SECS), move || {
|
||||||
|
// Notify about error
|
||||||
|
let _ = tx2.send(Err(()));
|
||||||
|
// Resume handler
|
||||||
|
let _ = control2.ready(Next::read());
|
||||||
|
});
|
||||||
|
|
||||||
|
self.state = State::Waiting(rx, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
Next::wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_request_readable(&mut self, _decoder: &mut Decoder<HttpStream>) -> Next {
|
||||||
|
if let State::Waiting(rx, map) = mem::replace(&mut self.state, State::Invalid) {
|
||||||
|
match rx.try_recv() {
|
||||||
|
Ok(result) => {
|
||||||
|
self.state = State::Done(map(result));
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
warn!("Resuming handler in incorrect state: {:?}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Next::write()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_response(&mut self, res: &mut server::Response) -> Next {
|
||||||
|
if let State::Done(ref mut handler) = self.state {
|
||||||
|
handler.on_response(res)
|
||||||
|
} else {
|
||||||
|
Next::end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next {
|
||||||
|
if let State::Done(ref mut handler) = self.state {
|
||||||
|
handler.on_response_writable(encoder)
|
||||||
|
} else {
|
||||||
|
Next::end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -40,10 +40,6 @@ impl ContentHandler {
|
|||||||
Self::new(StatusCode::Ok, content, mimetype)
|
Self::new(StatusCode::Ok, content, mimetype)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn not_found(content: String, mimetype: Mime) -> Self {
|
|
||||||
Self::new(StatusCode::NotFound, content, mimetype)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn html(code: StatusCode, content: String, embeddable_on: Embeddable) -> Self {
|
pub fn html(code: StatusCode, content: String, embeddable_on: Embeddable) -> Self {
|
||||||
Self::new_embeddable(code, content, mime!(Text/Html), embeddable_on)
|
Self::new_embeddable(code, content, mime!(Text/Html), embeddable_on)
|
||||||
}
|
}
|
||||||
|
@ -16,18 +16,23 @@
|
|||||||
|
|
||||||
//! Hyper handlers implementations.
|
//! Hyper handlers implementations.
|
||||||
|
|
||||||
|
mod async;
|
||||||
mod content;
|
mod content;
|
||||||
mod echo;
|
mod echo;
|
||||||
mod fetch;
|
mod fetch;
|
||||||
mod redirect;
|
mod redirect;
|
||||||
mod streaming;
|
mod streaming;
|
||||||
|
|
||||||
|
pub use self::async::AsyncHandler;
|
||||||
pub use self::content::ContentHandler;
|
pub use self::content::ContentHandler;
|
||||||
pub use self::echo::EchoHandler;
|
pub use self::echo::EchoHandler;
|
||||||
pub use self::fetch::{ContentFetcherHandler, ContentValidator, FetchControl, ValidatorResponse};
|
pub use self::fetch::{ContentFetcherHandler, ContentValidator, FetchControl, ValidatorResponse};
|
||||||
pub use self::redirect::Redirection;
|
pub use self::redirect::Redirection;
|
||||||
pub use self::streaming::StreamingHandler;
|
pub use self::streaming::StreamingHandler;
|
||||||
|
|
||||||
|
use std::iter;
|
||||||
|
use util::Itertools;
|
||||||
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use hyper::{server, header, net, uri};
|
use hyper::{server, header, net, uri};
|
||||||
use {apps, address, Embeddable};
|
use {apps, address, Embeddable};
|
||||||
@ -78,21 +83,21 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embedd
|
|||||||
let proxy = format!("{}.{}", apps::HOME_PAGE, embed.dapps_domain);
|
let proxy = format!("{}.{}", apps::HOME_PAGE, embed.dapps_domain);
|
||||||
let domain = format!("*.{}:{}", embed.dapps_domain, embed.port);
|
let domain = format!("*.{}:{}", embed.dapps_domain, embed.port);
|
||||||
|
|
||||||
if embed.host == "127.0.0.1" {
|
let mut ancestors = vec![std, domain, proxy]
|
||||||
|
.into_iter()
|
||||||
|
.chain(embed.extra_embed_on
|
||||||
|
.iter()
|
||||||
|
.map(|&(ref host, port)| format!("{}:{}", host, port))
|
||||||
|
);
|
||||||
|
|
||||||
|
let ancestors = if embed.host == "127.0.0.1" {
|
||||||
let localhost = address("localhost", embed.port);
|
let localhost = address("localhost", embed.port);
|
||||||
format!("frame-ancestors {} {} {} {};",
|
ancestors.chain(iter::once(localhost)).join(" ")
|
||||||
std,
|
|
||||||
localhost,
|
|
||||||
domain,
|
|
||||||
proxy,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
format!("frame-ancestors {} {} {};",
|
ancestors.join(" ")
|
||||||
std,
|
};
|
||||||
domain,
|
|
||||||
proxy,
|
format!("frame-ancestors {};", ancestors)
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
None => format!("frame-ancestors 'self';"),
|
None => format!("frame-ancestors 'self';"),
|
||||||
}.into_bytes(),
|
}.into_bytes(),
|
||||||
|
@ -21,8 +21,10 @@
|
|||||||
|
|
||||||
extern crate base32;
|
extern crate base32;
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
|
extern crate futures_cpupool;
|
||||||
extern crate linked_hash_map;
|
extern crate linked_hash_map;
|
||||||
extern crate mime_guess;
|
extern crate mime_guess;
|
||||||
|
extern crate ntp;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate rustc_hex;
|
extern crate rustc_hex;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
@ -74,6 +76,7 @@ use std::collections::HashMap;
|
|||||||
use jsonrpc_http_server::{self as http, hyper, Origin};
|
use jsonrpc_http_server::{self as http, hyper, Origin};
|
||||||
|
|
||||||
use fetch::Fetch;
|
use fetch::Fetch;
|
||||||
|
use futures_cpupool::CpuPool;
|
||||||
use parity_reactor::Remote;
|
use parity_reactor::Remote;
|
||||||
|
|
||||||
pub use hash_fetch::urlhint::ContractClient;
|
pub use hash_fetch::urlhint::ContractClient;
|
||||||
@ -82,10 +85,9 @@ pub use hash_fetch::urlhint::ContractClient;
|
|||||||
pub trait SyncStatus: Send + Sync {
|
pub trait SyncStatus: Send + Sync {
|
||||||
/// Returns true if there is a major sync happening.
|
/// Returns true if there is a major sync happening.
|
||||||
fn is_major_importing(&self) -> bool;
|
fn is_major_importing(&self) -> bool;
|
||||||
}
|
|
||||||
|
|
||||||
impl<F> SyncStatus for F where F: Fn() -> bool + Send + Sync {
|
/// Returns number of connected and ideal peers.
|
||||||
fn is_major_importing(&self) -> bool { self() }
|
fn peers(&self) -> (usize, usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validates Web Proxy tokens
|
/// Validates Web Proxy tokens
|
||||||
@ -127,21 +129,29 @@ impl Middleware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates new middleware for UI server.
|
/// Creates new middleware for UI server.
|
||||||
pub fn ui<F: Fetch + Clone>(
|
pub fn ui<F: Fetch>(
|
||||||
|
ntp_server: &str,
|
||||||
|
pool: CpuPool,
|
||||||
remote: Remote,
|
remote: Remote,
|
||||||
|
dapps_domain: &str,
|
||||||
registrar: Arc<ContractClient>,
|
registrar: Arc<ContractClient>,
|
||||||
sync_status: Arc<SyncStatus>,
|
sync_status: Arc<SyncStatus>,
|
||||||
fetch: F,
|
fetch: F,
|
||||||
dapps_domain: String,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let content_fetcher = Arc::new(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.clone(),
|
||||||
remote.clone(),
|
remote.clone(),
|
||||||
fetch.clone(),
|
fetch.clone(),
|
||||||
).embeddable_on(None).allow_dapps(false));
|
).embeddable_on(None).allow_dapps(false));
|
||||||
let special = {
|
let special = {
|
||||||
let mut special = special_endpoints(content_fetcher.clone());
|
let mut special = special_endpoints(
|
||||||
|
ntp_server,
|
||||||
|
pool,
|
||||||
|
content_fetcher.clone(),
|
||||||
|
remote.clone(),
|
||||||
|
sync_status.clone(),
|
||||||
|
);
|
||||||
special.insert(router::SpecialEndpoint::Home, Some(apps::ui()));
|
special.insert(router::SpecialEndpoint::Home, Some(apps::ui()));
|
||||||
special
|
special
|
||||||
};
|
};
|
||||||
@ -150,7 +160,7 @@ impl Middleware {
|
|||||||
None,
|
None,
|
||||||
special,
|
special,
|
||||||
None,
|
None,
|
||||||
dapps_domain,
|
dapps_domain.to_owned(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Middleware {
|
Middleware {
|
||||||
@ -160,39 +170,48 @@ impl Middleware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates new Dapps server middleware.
|
/// Creates new Dapps server middleware.
|
||||||
pub fn dapps<F: Fetch + Clone>(
|
pub fn dapps<F: Fetch>(
|
||||||
|
ntp_server: &str,
|
||||||
|
pool: CpuPool,
|
||||||
remote: Remote,
|
remote: Remote,
|
||||||
ui_address: Option<(String, u16)>,
|
ui_address: Option<(String, u16)>,
|
||||||
|
extra_embed_on: Vec<(String, u16)>,
|
||||||
dapps_path: PathBuf,
|
dapps_path: PathBuf,
|
||||||
extra_dapps: Vec<PathBuf>,
|
extra_dapps: Vec<PathBuf>,
|
||||||
dapps_domain: String,
|
dapps_domain: &str,
|
||||||
registrar: Arc<ContractClient>,
|
registrar: Arc<ContractClient>,
|
||||||
sync_status: Arc<SyncStatus>,
|
sync_status: Arc<SyncStatus>,
|
||||||
web_proxy_tokens: Arc<WebProxyTokens>,
|
web_proxy_tokens: Arc<WebProxyTokens>,
|
||||||
fetch: F,
|
fetch: F,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let embeddable = as_embeddable(ui_address.clone(), dapps_domain.clone());
|
let embeddable = as_embeddable(ui_address, extra_embed_on, dapps_domain);
|
||||||
let content_fetcher = Arc::new(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.clone(),
|
||||||
remote.clone(),
|
remote.clone(),
|
||||||
fetch.clone(),
|
fetch.clone(),
|
||||||
).embeddable_on(embeddable.clone()).allow_dapps(true));
|
).embeddable_on(embeddable.clone()).allow_dapps(true));
|
||||||
let endpoints = apps::all_endpoints(
|
let endpoints = apps::all_endpoints(
|
||||||
dapps_path,
|
dapps_path,
|
||||||
extra_dapps,
|
extra_dapps,
|
||||||
dapps_domain.clone(),
|
dapps_domain,
|
||||||
ui_address.clone(),
|
embeddable.clone(),
|
||||||
web_proxy_tokens,
|
web_proxy_tokens,
|
||||||
remote.clone(),
|
remote.clone(),
|
||||||
fetch.clone(),
|
fetch.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let special = {
|
let special = {
|
||||||
let mut special = special_endpoints(content_fetcher.clone());
|
let mut special = special_endpoints(
|
||||||
|
ntp_server,
|
||||||
|
pool,
|
||||||
|
content_fetcher.clone(),
|
||||||
|
remote.clone(),
|
||||||
|
sync_status,
|
||||||
|
);
|
||||||
special.insert(
|
special.insert(
|
||||||
router::SpecialEndpoint::Home,
|
router::SpecialEndpoint::Home,
|
||||||
Some(apps::ui_redirection(ui_address.clone(), dapps_domain.clone())),
|
Some(apps::ui_redirection(embeddable.clone())),
|
||||||
);
|
);
|
||||||
special
|
special
|
||||||
};
|
};
|
||||||
@ -202,7 +221,7 @@ impl Middleware {
|
|||||||
Some(endpoints.clone()),
|
Some(endpoints.clone()),
|
||||||
special,
|
special,
|
||||||
embeddable,
|
embeddable,
|
||||||
dapps_domain,
|
dapps_domain.to_owned(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Middleware {
|
Middleware {
|
||||||
@ -218,11 +237,22 @@ impl http::RequestMiddleware for Middleware {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn special_endpoints(content_fetcher: Arc<apps::fetcher::Fetcher>) -> HashMap<router::SpecialEndpoint, Option<Box<endpoint::Endpoint>>> {
|
fn special_endpoints(
|
||||||
|
ntp_server: &str,
|
||||||
|
pool: CpuPool,
|
||||||
|
content_fetcher: Arc<apps::fetcher::Fetcher>,
|
||||||
|
remote: Remote,
|
||||||
|
sync_status: Arc<SyncStatus>,
|
||||||
|
) -> HashMap<router::SpecialEndpoint, Option<Box<endpoint::Endpoint>>> {
|
||||||
let mut special = HashMap::new();
|
let mut special = HashMap::new();
|
||||||
special.insert(router::SpecialEndpoint::Rpc, None);
|
special.insert(router::SpecialEndpoint::Rpc, None);
|
||||||
special.insert(router::SpecialEndpoint::Utils, Some(apps::utils()));
|
special.insert(router::SpecialEndpoint::Utils, Some(apps::utils()));
|
||||||
special.insert(router::SpecialEndpoint::Api, Some(api::RestApi::new(content_fetcher)));
|
special.insert(router::SpecialEndpoint::Api, Some(api::RestApi::new(
|
||||||
|
content_fetcher,
|
||||||
|
sync_status,
|
||||||
|
api::TimeChecker::new(ntp_server.into(), pool),
|
||||||
|
remote,
|
||||||
|
)));
|
||||||
special
|
special
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,8 +260,17 @@ fn address(host: &str, port: u16) -> String {
|
|||||||
format!("{}:{}", host, port)
|
format!("{}:{}", host, port)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_embeddable(ui_address: Option<(String, u16)>, dapps_domain: String) -> Option<ParentFrameSettings> {
|
fn as_embeddable(
|
||||||
ui_address.map(|(host, port)| ParentFrameSettings { host, port, dapps_domain, })
|
ui_address: Option<(String, u16)>,
|
||||||
|
extra_embed_on: Vec<(String, u16)>,
|
||||||
|
dapps_domain: &str,
|
||||||
|
) -> Option<ParentFrameSettings> {
|
||||||
|
ui_address.map(|(host, port)| ParentFrameSettings {
|
||||||
|
host,
|
||||||
|
port,
|
||||||
|
extra_embed_on,
|
||||||
|
dapps_domain: dapps_domain.to_owned(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Random filename
|
/// Random filename
|
||||||
@ -250,6 +289,8 @@ pub struct ParentFrameSettings {
|
|||||||
pub host: String,
|
pub host: String,
|
||||||
/// Port
|
/// Port
|
||||||
pub port: u16,
|
pub port: u16,
|
||||||
|
/// Additional pages the pages can be embedded on.
|
||||||
|
pub extra_embed_on: Vec<(String, u16)>,
|
||||||
/// Dapps Domain (web3.site)
|
/// Dapps Domain (web3.site)
|
||||||
pub dapps_domain: String,
|
pub dapps_domain: String,
|
||||||
}
|
}
|
||||||
|
@ -19,27 +19,24 @@
|
|||||||
use endpoint::{Endpoint, Handler, EndpointPath};
|
use endpoint::{Endpoint, Handler, EndpointPath};
|
||||||
use handlers::ContentHandler;
|
use handlers::ContentHandler;
|
||||||
use apps::HOME_PAGE;
|
use apps::HOME_PAGE;
|
||||||
use address;
|
use {address, Embeddable};
|
||||||
|
|
||||||
pub struct ProxyPac {
|
pub struct ProxyPac {
|
||||||
signer_address: Option<(String, u16)>,
|
embeddable: Embeddable,
|
||||||
dapps_domain: String,
|
dapps_domain: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProxyPac {
|
impl ProxyPac {
|
||||||
pub fn boxed(signer_address: Option<(String, u16)>, dapps_domain: String) -> Box<Endpoint> {
|
pub fn boxed(embeddable: Embeddable, dapps_domain: String) -> Box<Endpoint> {
|
||||||
Box::new(ProxyPac {
|
Box::new(ProxyPac { embeddable, dapps_domain })
|
||||||
signer_address: signer_address,
|
|
||||||
dapps_domain: dapps_domain,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Endpoint for ProxyPac {
|
impl Endpoint for ProxyPac {
|
||||||
fn to_handler(&self, path: EndpointPath) -> Box<Handler> {
|
fn to_handler(&self, path: EndpointPath) -> Box<Handler> {
|
||||||
let signer = self.signer_address
|
let ui = self.embeddable
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|&(ref host, port)| address(host, port))
|
.map(|ref parent| address(&parent.host, parent.port))
|
||||||
.unwrap_or_else(|| format!("{}:{}", path.host, path.port));
|
.unwrap_or_else(|| format!("{}:{}", path.host, path.port));
|
||||||
|
|
||||||
let content = format!(
|
let content = format!(
|
||||||
@ -58,7 +55,7 @@ function FindProxyForURL(url, host) {{
|
|||||||
return "DIRECT";
|
return "DIRECT";
|
||||||
}}
|
}}
|
||||||
"#,
|
"#,
|
||||||
HOME_PAGE, self.dapps_domain, path.host, path.port, signer);
|
HOME_PAGE, self.dapps_domain, path.host, path.port, ui);
|
||||||
|
|
||||||
Box::new(ContentHandler::ok(content, mime!(Application/Javascript)))
|
Box::new(ContentHandler::ok(content, mime!(Application/Javascript)))
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ use jsonrpc_http_server::{self as http, Host, DomainsValidation};
|
|||||||
use devtools::http_client;
|
use devtools::http_client;
|
||||||
use hash_fetch::urlhint::ContractClient;
|
use hash_fetch::urlhint::ContractClient;
|
||||||
use fetch::{Fetch, Client as FetchClient};
|
use fetch::{Fetch, Client as FetchClient};
|
||||||
|
use futures_cpupool::CpuPool;
|
||||||
use parity_reactor::Remote;
|
use parity_reactor::Remote;
|
||||||
|
|
||||||
use {Middleware, SyncStatus, WebProxyTokens};
|
use {Middleware, SyncStatus, WebProxyTokens};
|
||||||
@ -38,6 +39,12 @@ use self::fetch::FakeFetch;
|
|||||||
|
|
||||||
const SIGNER_PORT: u16 = 18180;
|
const SIGNER_PORT: u16 = 18180;
|
||||||
|
|
||||||
|
struct FakeSync(bool);
|
||||||
|
impl SyncStatus for FakeSync {
|
||||||
|
fn is_major_importing(&self) -> bool { self.0 }
|
||||||
|
fn peers(&self) -> (usize, usize) { (0, 5) }
|
||||||
|
}
|
||||||
|
|
||||||
fn init_logger() {
|
fn init_logger() {
|
||||||
// Initialize logger
|
// Initialize logger
|
||||||
if let Ok(log) = env::var("RUST_LOG") {
|
if let Ok(log) = env::var("RUST_LOG") {
|
||||||
@ -82,7 +89,7 @@ pub fn serve_with_registrar() -> (Server, Arc<FakeRegistrar>) {
|
|||||||
|
|
||||||
pub fn serve_with_registrar_and_sync() -> (Server, Arc<FakeRegistrar>) {
|
pub fn serve_with_registrar_and_sync() -> (Server, Arc<FakeRegistrar>) {
|
||||||
init_server(|builder| {
|
init_server(|builder| {
|
||||||
builder.sync_status(Arc::new(|| true))
|
builder.sync_status(Arc::new(FakeSync(true)))
|
||||||
}, Default::default(), Remote::new_sync())
|
}, Default::default(), Remote::new_sync())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +155,7 @@ impl ServerBuilder {
|
|||||||
ServerBuilder {
|
ServerBuilder {
|
||||||
dapps_path: dapps_path.as_ref().to_owned(),
|
dapps_path: dapps_path.as_ref().to_owned(),
|
||||||
registrar: registrar,
|
registrar: registrar,
|
||||||
sync_status: Arc::new(|| false),
|
sync_status: Arc::new(FakeSync(false)),
|
||||||
web_proxy_tokens: Arc::new(|_| None),
|
web_proxy_tokens: Arc::new(|_| None),
|
||||||
signer_address: None,
|
signer_address: None,
|
||||||
allowed_hosts: DomainsValidation::Disabled,
|
allowed_hosts: DomainsValidation::Disabled,
|
||||||
@ -248,8 +255,11 @@ impl Server {
|
|||||||
fetch: F,
|
fetch: F,
|
||||||
) -> Result<Server, http::Error> {
|
) -> Result<Server, http::Error> {
|
||||||
let middleware = Middleware::dapps(
|
let middleware = Middleware::dapps(
|
||||||
|
"pool.ntp.org:123",
|
||||||
|
CpuPool::new(4),
|
||||||
remote,
|
remote,
|
||||||
signer_address,
|
signer_address,
|
||||||
|
vec![],
|
||||||
dapps_path,
|
dapps_path,
|
||||||
extra_dapps,
|
extra_dapps,
|
||||||
DAPPS_DOMAIN.into(),
|
DAPPS_DOMAIN.into(),
|
||||||
@ -290,4 +300,3 @@ impl Drop for Server {
|
|||||||
self.server.take().unwrap().close()
|
self.server.take().unwrap().close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ use std::mem;
|
|||||||
use std::ptr;
|
use std::ptr;
|
||||||
use sha3;
|
use sha3;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::path::PathBuf;
|
use std::path::{Path, PathBuf};
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
|
|
||||||
@ -86,6 +86,7 @@ impl Node {
|
|||||||
pub type H256 = [u8; 32];
|
pub type H256 = [u8; 32];
|
||||||
|
|
||||||
pub struct Light {
|
pub struct Light {
|
||||||
|
cache_dir: PathBuf,
|
||||||
block_number: u64,
|
block_number: u64,
|
||||||
cache: Vec<Node>,
|
cache: Vec<Node>,
|
||||||
seed_compute: Mutex<SeedHashCompute>,
|
seed_compute: Mutex<SeedHashCompute>,
|
||||||
@ -94,8 +95,8 @@ pub struct Light {
|
|||||||
/// Light cache structure
|
/// Light cache structure
|
||||||
impl Light {
|
impl Light {
|
||||||
/// Create a new light cache for a given block number
|
/// Create a new light cache for a given block number
|
||||||
pub fn new(block_number: u64) -> Light {
|
pub fn new<T: AsRef<Path>>(cache_dir: T, block_number: u64) -> Light {
|
||||||
light_new(block_number)
|
light_new(cache_dir, block_number)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate the light boundary data
|
/// Calculate the light boundary data
|
||||||
@ -105,17 +106,15 @@ impl Light {
|
|||||||
light_compute(self, header_hash, nonce)
|
light_compute(self, header_hash, nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_path(seed_hash: H256) -> PathBuf {
|
pub fn file_path<T: AsRef<Path>>(cache_dir: T, seed_hash: H256) -> PathBuf {
|
||||||
let mut home = ::std::env::home_dir().unwrap();
|
let mut cache_dir = cache_dir.as_ref().to_path_buf();
|
||||||
home.push(".ethash");
|
cache_dir.push(to_hex(&seed_hash));
|
||||||
home.push("light");
|
cache_dir
|
||||||
home.push(to_hex(&seed_hash));
|
|
||||||
home
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_file(block_number: u64) -> io::Result<Light> {
|
pub fn from_file<T: AsRef<Path>>(cache_dir: T, block_number: u64) -> io::Result<Light> {
|
||||||
let seed_compute = SeedHashCompute::new();
|
let seed_compute = SeedHashCompute::new();
|
||||||
let path = Light::file_path(seed_compute.get_seedhash(block_number));
|
let path = Light::file_path(&cache_dir, seed_compute.get_seedhash(block_number));
|
||||||
let mut file = File::open(path)?;
|
let mut file = File::open(path)?;
|
||||||
|
|
||||||
let cache_size = get_cache_size(block_number);
|
let cache_size = get_cache_size(block_number);
|
||||||
@ -128,19 +127,22 @@ impl Light {
|
|||||||
let buf = unsafe { slice::from_raw_parts_mut(nodes.as_mut_ptr() as *mut u8, cache_size) };
|
let buf = unsafe { slice::from_raw_parts_mut(nodes.as_mut_ptr() as *mut u8, cache_size) };
|
||||||
file.read_exact(buf)?;
|
file.read_exact(buf)?;
|
||||||
Ok(Light {
|
Ok(Light {
|
||||||
|
block_number,
|
||||||
|
cache_dir: cache_dir.as_ref().to_path_buf(),
|
||||||
cache: nodes,
|
cache: nodes,
|
||||||
block_number: block_number,
|
|
||||||
seed_compute: Mutex::new(seed_compute),
|
seed_compute: Mutex::new(seed_compute),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_file(&self) -> io::Result<PathBuf> {
|
pub fn to_file(&self) -> io::Result<PathBuf> {
|
||||||
let seed_compute = self.seed_compute.lock();
|
let seed_compute = self.seed_compute.lock();
|
||||||
let path = Light::file_path(seed_compute.get_seedhash(self.block_number));
|
let path = Light::file_path(&self.cache_dir, seed_compute.get_seedhash(self.block_number));
|
||||||
|
|
||||||
if self.block_number >= ETHASH_EPOCH_LENGTH * 2 {
|
if self.block_number >= ETHASH_EPOCH_LENGTH * 2 {
|
||||||
let deprecated = Light::file_path(
|
let deprecated = Light::file_path(
|
||||||
seed_compute.get_seedhash(self.block_number - ETHASH_EPOCH_LENGTH * 2));
|
&self.cache_dir,
|
||||||
|
seed_compute.get_seedhash(self.block_number - ETHASH_EPOCH_LENGTH * 2)
|
||||||
|
);
|
||||||
|
|
||||||
if deprecated.exists() {
|
if deprecated.exists() {
|
||||||
debug!(target: "ethash", "removing: {:?}", &deprecated);
|
debug!(target: "ethash", "removing: {:?}", &deprecated);
|
||||||
@ -341,14 +343,12 @@ fn calculate_dag_item(node_index: u32, cache: &[Node]) -> Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn light_new(block_number: u64) -> Light {
|
fn light_new<T: AsRef<Path>>(cache_dir: T, block_number: u64) -> Light {
|
||||||
let seed_compute = SeedHashCompute::new();
|
let seed_compute = SeedHashCompute::new();
|
||||||
let seedhash = seed_compute.get_seedhash(block_number);
|
let seedhash = seed_compute.get_seedhash(block_number);
|
||||||
let cache_size = get_cache_size(block_number);
|
let cache_size = get_cache_size(block_number);
|
||||||
|
|
||||||
if cache_size % NODE_BYTES != 0 {
|
assert!(cache_size % NODE_BYTES == 0, "Unaligned cache size");
|
||||||
panic!("Unaligned cache size");
|
|
||||||
}
|
|
||||||
let num_nodes = cache_size / NODE_BYTES;
|
let num_nodes = cache_size / NODE_BYTES;
|
||||||
|
|
||||||
let mut nodes = Vec::with_capacity(num_nodes);
|
let mut nodes = Vec::with_capacity(num_nodes);
|
||||||
@ -372,8 +372,9 @@ fn light_new(block_number: u64) -> Light {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Light {
|
Light {
|
||||||
|
block_number,
|
||||||
|
cache_dir: cache_dir.as_ref().to_path_buf(),
|
||||||
cache: nodes,
|
cache: nodes,
|
||||||
block_number: block_number,
|
|
||||||
seed_compute: Mutex::new(seed_compute),
|
seed_compute: Mutex::new(seed_compute),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -432,7 +433,7 @@ fn test_light_compute() {
|
|||||||
let boundary = [0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3e, 0x9b, 0x6c, 0x69, 0xbc, 0x2c, 0xe2, 0xa2, 0x4a, 0x8e, 0x95, 0x69, 0xef, 0xc7, 0xd7, 0x1b, 0x33, 0x35, 0xdf, 0x36, 0x8c, 0x9a, 0xe9, 0x7e, 0x53, 0x84];
|
let boundary = [0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3e, 0x9b, 0x6c, 0x69, 0xbc, 0x2c, 0xe2, 0xa2, 0x4a, 0x8e, 0x95, 0x69, 0xef, 0xc7, 0xd7, 0x1b, 0x33, 0x35, 0xdf, 0x36, 0x8c, 0x9a, 0xe9, 0x7e, 0x53, 0x84];
|
||||||
let nonce = 0xd7b3ac70a301a249;
|
let nonce = 0xd7b3ac70a301a249;
|
||||||
// difficulty = 0x085657254bd9u64;
|
// difficulty = 0x085657254bd9u64;
|
||||||
let light = Light::new(486382);
|
let light = Light::new(&::std::env::temp_dir(), 486382);
|
||||||
let result = light_compute(&light, &hash, nonce);
|
let result = light_compute(&light, &hash, nonce);
|
||||||
assert_eq!(result.mix_hash[..], mix_hash[..]);
|
assert_eq!(result.mix_hash[..], mix_hash[..]);
|
||||||
assert_eq!(result.value[..], boundary[..]);
|
assert_eq!(result.value[..], boundary[..]);
|
||||||
@ -471,15 +472,16 @@ fn test_seed_compute_after_newer() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_drop_old_data() {
|
fn test_drop_old_data() {
|
||||||
let first = Light::new(0).to_file().unwrap();
|
let path = ::std::env::temp_dir();
|
||||||
|
let first = Light::new(&path, 0).to_file().unwrap();
|
||||||
|
|
||||||
let second = Light::new(ETHASH_EPOCH_LENGTH).to_file().unwrap();
|
let second = Light::new(&path, ETHASH_EPOCH_LENGTH).to_file().unwrap();
|
||||||
assert!(fs::metadata(&first).is_ok());
|
assert!(fs::metadata(&first).is_ok());
|
||||||
|
|
||||||
let _ = Light::new(ETHASH_EPOCH_LENGTH * 2).to_file();
|
let _ = Light::new(&path, ETHASH_EPOCH_LENGTH * 2).to_file();
|
||||||
assert!(fs::metadata(&first).is_err());
|
assert!(fs::metadata(&first).is_err());
|
||||||
assert!(fs::metadata(&second).is_ok());
|
assert!(fs::metadata(&second).is_ok());
|
||||||
|
|
||||||
let _ = Light::new(ETHASH_EPOCH_LENGTH * 3).to_file();
|
let _ = Light::new(&path, ETHASH_EPOCH_LENGTH * 3).to_file();
|
||||||
assert!(fs::metadata(&second).is_err());
|
assert!(fs::metadata(&second).is_err());
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ extern crate log;
|
|||||||
mod compute;
|
mod compute;
|
||||||
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
use compute::Light;
|
use compute::Light;
|
||||||
pub use compute::{ETHASH_EPOCH_LENGTH, H256, ProofOfWork, SeedHashCompute, quick_get_difficulty, slow_get_seedhash};
|
pub use compute::{ETHASH_EPOCH_LENGTH, H256, ProofOfWork, SeedHashCompute, quick_get_difficulty, slow_get_seedhash};
|
||||||
|
|
||||||
@ -41,12 +42,14 @@ struct LightCache {
|
|||||||
/// Light/Full cache manager.
|
/// Light/Full cache manager.
|
||||||
pub struct EthashManager {
|
pub struct EthashManager {
|
||||||
cache: Mutex<LightCache>,
|
cache: Mutex<LightCache>,
|
||||||
|
cache_dir: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EthashManager {
|
impl EthashManager {
|
||||||
/// Create a new new instance of ethash manager
|
/// Create a new new instance of ethash manager
|
||||||
pub fn new() -> EthashManager {
|
pub fn new<T: AsRef<Path>>(cache_dir: T) -> EthashManager {
|
||||||
EthashManager {
|
EthashManager {
|
||||||
|
cache_dir: cache_dir.as_ref().to_path_buf(),
|
||||||
cache: Mutex::new(LightCache {
|
cache: Mutex::new(LightCache {
|
||||||
recent_epoch: None,
|
recent_epoch: None,
|
||||||
recent: None,
|
recent: None,
|
||||||
@ -88,11 +91,11 @@ impl EthashManager {
|
|||||||
};
|
};
|
||||||
match light {
|
match light {
|
||||||
None => {
|
None => {
|
||||||
let light = match Light::from_file(block_number) {
|
let light = match Light::from_file(&self.cache_dir, block_number) {
|
||||||
Ok(light) => Arc::new(light),
|
Ok(light) => Arc::new(light),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
debug!("Light cache file not found for {}:{}", block_number, e);
|
debug!("Light cache file not found for {}:{}", block_number, e);
|
||||||
let light = Light::new(block_number);
|
let light = Light::new(&self.cache_dir, block_number);
|
||||||
if let Err(e) = light.to_file() {
|
if let Err(e) = light.to_file() {
|
||||||
warn!("Light cache file write error: {}", e);
|
warn!("Light cache file write error: {}", e);
|
||||||
}
|
}
|
||||||
@ -112,7 +115,7 @@ impl EthashManager {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_lru() {
|
fn test_lru() {
|
||||||
let ethash = EthashManager::new();
|
let ethash = EthashManager::new(&::std::env::temp_dir());
|
||||||
let hash = [0u8; 32];
|
let hash = [0u8; 32];
|
||||||
ethash.compute_light(1, &hash, 1);
|
ethash.compute_light(1, &hash, 1);
|
||||||
ethash.compute_light(50000, &hash, 1);
|
ethash.compute_light(50000, &hash, 1);
|
||||||
|
@ -52,6 +52,8 @@ semver = "0.6"
|
|||||||
stats = { path = "../util/stats" }
|
stats = { path = "../util/stats" }
|
||||||
time = "0.1"
|
time = "0.1"
|
||||||
transient-hashmap = "0.4"
|
transient-hashmap = "0.4"
|
||||||
|
parity-wasm = "0.12"
|
||||||
|
wasm-utils = { git = "https://github.com/paritytech/wasm-utils" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
native-contracts = { path = "native_contracts", features = ["test_contracts"] }
|
native-contracts = { path = "native_contracts", features = ["test_contracts"] }
|
||||||
|
@ -26,7 +26,7 @@ use ethcore::receipt::Receipt;
|
|||||||
|
|
||||||
use stats::Corpus;
|
use stats::Corpus;
|
||||||
use time::{SteadyTime, Duration};
|
use time::{SteadyTime, Duration};
|
||||||
use util::{U256, H256};
|
use util::{U256, H256, HeapSizeOf};
|
||||||
use util::cache::MemoryLruCache;
|
use util::cache::MemoryLruCache;
|
||||||
|
|
||||||
/// Configuration for how much data to cache.
|
/// Configuration for how much data to cache.
|
||||||
@ -153,6 +153,22 @@ impl Cache {
|
|||||||
pub fn set_gas_price_corpus(&mut self, corpus: Corpus<U256>) {
|
pub fn set_gas_price_corpus(&mut self, corpus: Corpus<U256>) {
|
||||||
self.corpus = Some((corpus, SteadyTime::now()))
|
self.corpus = Some((corpus, SteadyTime::now()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the memory used.
|
||||||
|
pub fn mem_used(&self) -> usize {
|
||||||
|
self.heap_size_of_children()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeapSizeOf for Cache {
|
||||||
|
fn heap_size_of_children(&self) -> usize {
|
||||||
|
self.headers.current_size()
|
||||||
|
+ self.canon_hashes.current_size()
|
||||||
|
+ self.bodies.current_size()
|
||||||
|
+ self.receipts.current_size()
|
||||||
|
+ self.chain_score.current_size()
|
||||||
|
// TODO: + corpus
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -44,7 +44,7 @@ mod header_chain;
|
|||||||
mod service;
|
mod service;
|
||||||
|
|
||||||
/// Configuration for the light client.
|
/// Configuration for the light client.
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
/// Verification queue config.
|
/// Verification queue config.
|
||||||
pub queue: queue::Config,
|
pub queue: queue::Config,
|
||||||
@ -56,6 +56,21 @@ pub struct Config {
|
|||||||
pub db_compaction: CompactionProfile,
|
pub db_compaction: CompactionProfile,
|
||||||
/// Should db have WAL enabled?
|
/// Should db have WAL enabled?
|
||||||
pub db_wal: bool,
|
pub db_wal: bool,
|
||||||
|
/// Should it do full verification of blocks?
|
||||||
|
pub verify_full: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Config {
|
||||||
|
fn default() -> Config {
|
||||||
|
Config {
|
||||||
|
queue: Default::default(),
|
||||||
|
chain_column: None,
|
||||||
|
db_cache_size: None,
|
||||||
|
db_compaction: CompactionProfile::default(),
|
||||||
|
db_wal: true,
|
||||||
|
verify_full: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait for interacting with the header chain abstractly.
|
/// Trait for interacting with the header chain abstractly.
|
||||||
@ -109,6 +124,9 @@ pub trait LightChainClient: Send + Sync {
|
|||||||
|
|
||||||
/// Get the EIP-86 transition block number.
|
/// Get the EIP-86 transition block number.
|
||||||
fn eip86_transition(&self) -> u64;
|
fn eip86_transition(&self) -> u64;
|
||||||
|
|
||||||
|
/// Get a report of import activity since the last call.
|
||||||
|
fn report(&self) -> ClientReport;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An actor listening to light chain events.
|
/// An actor listening to light chain events.
|
||||||
@ -141,6 +159,7 @@ pub struct Client {
|
|||||||
import_lock: Mutex<()>,
|
import_lock: Mutex<()>,
|
||||||
db: Arc<KeyValueDB>,
|
db: Arc<KeyValueDB>,
|
||||||
listeners: RwLock<Vec<Weak<LightChainNotify>>>,
|
listeners: RwLock<Vec<Weak<LightChainNotify>>>,
|
||||||
|
verify_full: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
@ -156,6 +175,7 @@ impl Client {
|
|||||||
import_lock: Mutex::new(()),
|
import_lock: Mutex::new(()),
|
||||||
db: db,
|
db: db,
|
||||||
listeners: RwLock::new(vec![]),
|
listeners: RwLock::new(vec![]),
|
||||||
|
verify_full: config.verify_full,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,6 +283,14 @@ impl Client {
|
|||||||
for verified_header in self.queue.drain(MAX) {
|
for verified_header in self.queue.drain(MAX) {
|
||||||
let (num, hash) = (verified_header.number(), verified_header.hash());
|
let (num, hash) = (verified_header.number(), verified_header.hash());
|
||||||
|
|
||||||
|
if self.verify_full && !self.check_header(&mut bad, &verified_header) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: `epoch_end_signal`, `is_epoch_end`.
|
||||||
|
// proofs we get from the network would be _complete_, whereas we need
|
||||||
|
// _incomplete_ signals
|
||||||
|
|
||||||
let mut tx = self.db.transaction();
|
let mut tx = self.db.transaction();
|
||||||
let pending = match self.chain.insert(&mut tx, verified_header) {
|
let pending = match self.chain.insert(&mut tx, verified_header) {
|
||||||
Ok(pending) => {
|
Ok(pending) => {
|
||||||
@ -273,15 +301,17 @@ impl Client {
|
|||||||
Err(e) => {
|
Err(e) => {
|
||||||
debug!(target: "client", "Error importing header {:?}: {}", (num, hash), e);
|
debug!(target: "client", "Error importing header {:?}: {}", (num, hash), e);
|
||||||
bad.push(hash);
|
bad.push(hash);
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.db.write_buffered(tx);
|
self.db.write_buffered(tx);
|
||||||
self.chain.apply_pending(pending);
|
self.chain.apply_pending(pending);
|
||||||
|
}
|
||||||
|
|
||||||
if let Err(e) = self.db.flush() {
|
if let Err(e) = self.db.flush() {
|
||||||
panic!("Database flush failed: {}. Check disk health and space.", e);
|
panic!("Database flush failed: {}. Check disk health and space.", e);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
self.queue.mark_as_bad(&bad);
|
self.queue.mark_as_bad(&bad);
|
||||||
self.queue.mark_as_good(&good);
|
self.queue.mark_as_good(&good);
|
||||||
@ -291,7 +321,7 @@ impl Client {
|
|||||||
|
|
||||||
/// Get a report about blocks imported.
|
/// Get a report about blocks imported.
|
||||||
pub fn report(&self) -> ClientReport {
|
pub fn report(&self) -> ClientReport {
|
||||||
::std::mem::replace(&mut *self.report.write(), ClientReport::default())
|
self.report.read().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get blockchain mem usage in bytes.
|
/// Get blockchain mem usage in bytes.
|
||||||
@ -350,6 +380,37 @@ impl Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return true if should skip, false otherwise. may push onto bad if
|
||||||
|
// should skip.
|
||||||
|
fn check_header(&self, bad: &mut Vec<H256>, verified_header: &Header) -> bool {
|
||||||
|
let hash = verified_header.hash();
|
||||||
|
let parent_header = match self.chain.block_header(BlockId::Hash(*verified_header.parent_hash())) {
|
||||||
|
Some(header) => header,
|
||||||
|
None => return false, // skip import of block with missing parent.
|
||||||
|
};
|
||||||
|
|
||||||
|
// Verify Block Family
|
||||||
|
let verify_family_result = self.engine.verify_block_family(&verified_header, &parent_header.decode(), None);
|
||||||
|
if let Err(e) = verify_family_result {
|
||||||
|
warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}",
|
||||||
|
verified_header.number(), verified_header.hash(), e);
|
||||||
|
bad.push(hash);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// "external" verification.
|
||||||
|
let verify_external_result = self.engine.verify_block_external(&verified_header, None);
|
||||||
|
if let Err(e) = verify_external_result {
|
||||||
|
warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}",
|
||||||
|
verified_header.number(), verified_header.hash(), e);
|
||||||
|
|
||||||
|
bad.push(hash);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LightChainClient for Client {
|
impl LightChainClient for Client {
|
||||||
@ -414,4 +475,8 @@ impl LightChainClient for Client {
|
|||||||
fn eip86_transition(&self) -> u64 {
|
fn eip86_transition(&self) -> u64 {
|
||||||
self.engine().params().eip86_transition
|
self.engine().params().eip86_transition
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn report(&self) -> ClientReport {
|
||||||
|
Client::report(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,10 +54,10 @@
|
|||||||
"0x00521965e7bd230323c423d96c657db5b79d099f": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }
|
"0x00521965e7bd230323c423d96c657db5b79d099f": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }
|
||||||
},
|
},
|
||||||
"nodes": [
|
"nodes": [
|
||||||
"enode://c005dd308256c60fab247813d8bf6d6e81f9cd354287837eb1c2fcf294adaa913a3208e88900ef5c55a8cba7042c301d80503edec2ad3f92a72e241ee6743854@192.241.230.87:30303",
|
"enode://0518a3d35d4a7b3e8c433e7ffd2355d84a1304ceb5ef349787b556197f0c87fad09daed760635b97d52179d645d3e6d16a37d2cc0a9945c2ddf585684beb39ac@40.68.248.100:30303",
|
||||||
"enode://48caeceb2724f2f71406990aa81efe87f8c53f26441d891473da2ae50cc138f238addc0e46b5aee240db55de8c711daac53d7b32a3f13e30edb86a3ca7c2700b@138.68.143.220:30303",
|
"enode://dcf984764db421fa0cd8dc7fc02ae378545723abb94d179f55325514cc30185eaea3dcefde6e358b7cdbe970c50b7c49e841618713a9a72d6f3f59ad9949ec6b@52.165.239.18:30303",
|
||||||
"enode://85705212fd28ebdd56669fb55e958feb9d81f74fe76c82f867564b6c2995e69f596df0f588eba16f1a43b69ce06485d68231a0c83fed8469b41eba0e390c126f@139.59.146.42:30303",
|
"enode://7e2e7f00784f516939f94e22bdc6cf96153603ca2b5df1c7cc0f90a38e7a2f218ffb1c05b156835e8b49086d11fdd1b3e2965be16baa55204167aa9bf536a4d9@52.243.47.56:30303",
|
||||||
"enode://2aa81bd0a761cd4f02c934dcf3f81c5b65953e51ab5ba03ceb1f125eb06418a1cdffb1c9d01871aa7bd456f3fce35e745608189ad1164f72b2161634b0c3f6ea@188.166.240.190:30303",
|
"enode://d51b3e98bf35addf2f1d0ea1ffc90483e24d7c60b0fb3be1701e818f3d6778c06e53fdec737a534fe222956296f9d6e909baa025916a94601897e5c7136a7d95@40.71.221.215:30303",
|
||||||
"enode://c5900cdd6d20795d58372f42dfbab9d664c27bb97e9c27972741942736e919122f9bac28e74cbc58e4ff195475ea90d9880b71a37af5b5a8cb41d843f765cff8@174.138.79.48:30303"
|
"enode://419d42e300e8fd379ff6d045d93d7e66a091441e7b3c9f1d3d10088d8634ad37721e6bf86148f78c3f1b9f1360dc566ca8ee830b2d2079bc9f7171ea6152bb64@52.166.117.77:30303"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
1
ethcore/res/wasm-tests
Submodule
1
ethcore/res/wasm-tests
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 9ed6304313fa949ed92aa0570fb2bc759fb6dc58
|
@ -39,6 +39,16 @@ impl ActionValue {
|
|||||||
ActionValue::Transfer(x) | ActionValue::Apparent(x) => x
|
ActionValue::Transfer(x) | ActionValue::Apparent(x) => x
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the transfer action value of the U256-convertable raw value
|
||||||
|
pub fn transfer<T: Into<U256>>(transfer_value: T) -> ActionValue {
|
||||||
|
ActionValue::Transfer(transfer_value.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the apparent action value of the U256-convertable raw value
|
||||||
|
pub fn apparent<T: Into<U256>>(apparent_value: T) -> ActionValue {
|
||||||
|
ActionValue::Apparent(apparent_value.into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: should be a trait, possible to avoid cloning everything from a Transaction(/View).
|
// TODO: should be a trait, possible to avoid cloning everything from a Transaction(/View).
|
||||||
|
@ -112,6 +112,22 @@ impl ClientReport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> ::std::ops::Sub<&'a ClientReport> for ClientReport {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(mut self, other: &'a ClientReport) -> Self {
|
||||||
|
let higher_mem = ::std::cmp::max(self.state_db_mem, other.state_db_mem);
|
||||||
|
let lower_mem = ::std::cmp::min(self.state_db_mem, other.state_db_mem);
|
||||||
|
|
||||||
|
self.blocks_imported -= other.blocks_imported;
|
||||||
|
self.transactions_applied -= other.transactions_applied;
|
||||||
|
self.gas_processed = self.gas_processed - other.gas_processed;
|
||||||
|
self.state_db_mem = higher_mem - lower_mem;
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct SleepState {
|
struct SleepState {
|
||||||
last_activity: Option<Instant>,
|
last_activity: Option<Instant>,
|
||||||
last_autosleep: Option<Instant>,
|
last_autosleep: Option<Instant>,
|
||||||
@ -1702,6 +1718,33 @@ impl MiningBlockChainClient for Client {
|
|||||||
open_block
|
open_block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reopen_block(&self, block: ClosedBlock) -> OpenBlock {
|
||||||
|
let engine = &*self.engine;
|
||||||
|
let mut block = block.reopen(engine);
|
||||||
|
let max_uncles = engine.maximum_uncle_count();
|
||||||
|
if block.uncles().len() < max_uncles {
|
||||||
|
let chain = self.chain.read();
|
||||||
|
let h = chain.best_block_hash();
|
||||||
|
// Add new uncles
|
||||||
|
let uncles = chain
|
||||||
|
.find_uncle_hashes(&h, engine.maximum_uncle_age())
|
||||||
|
.unwrap_or_else(Vec::new);
|
||||||
|
|
||||||
|
for h in uncles {
|
||||||
|
if !block.uncles().iter().any(|header| header.hash() == h) {
|
||||||
|
let uncle = chain.block_header(&h).expect("find_uncle_hashes only returns hashes for existing headers; qed");
|
||||||
|
block.push_uncle(uncle).expect("pushing up to maximum_uncle_count;
|
||||||
|
push_uncle is not ok only if more than maximum_uncle_count is pushed;
|
||||||
|
so all push_uncle are Ok;
|
||||||
|
qed");
|
||||||
|
if block.uncles().len() >= max_uncles { break }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
block
|
||||||
|
}
|
||||||
|
|
||||||
fn vm_factory(&self) -> &EvmFactory {
|
fn vm_factory(&self) -> &EvmFactory {
|
||||||
&self.factories.vm
|
&self.factories.vm
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ use types::mode::Mode;
|
|||||||
use types::pruning_info::PruningInfo;
|
use types::pruning_info::PruningInfo;
|
||||||
|
|
||||||
use verification::queue::QueueInfo;
|
use verification::queue::QueueInfo;
|
||||||
use block::{OpenBlock, SealedBlock};
|
use block::{OpenBlock, SealedBlock, ClosedBlock};
|
||||||
use executive::Executed;
|
use executive::Executed;
|
||||||
use error::CallError;
|
use error::CallError;
|
||||||
use trace::LocalizedTrace;
|
use trace::LocalizedTrace;
|
||||||
@ -381,6 +381,10 @@ impl MiningBlockChainClient for TestBlockChainClient {
|
|||||||
open_block
|
open_block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reopen_block(&self, block: ClosedBlock) -> OpenBlock {
|
||||||
|
block.reopen(&*self.spec.engine)
|
||||||
|
}
|
||||||
|
|
||||||
fn vm_factory(&self) -> &EvmFactory {
|
fn vm_factory(&self) -> &EvmFactory {
|
||||||
&self.vm_factory
|
&self.vm_factory
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ use util::{U256, Address, H256, H2048, Bytes, Itertools};
|
|||||||
use util::hashdb::DBValue;
|
use util::hashdb::DBValue;
|
||||||
use blockchain::TreeRoute;
|
use blockchain::TreeRoute;
|
||||||
use verification::queue::QueueInfo as BlockQueueInfo;
|
use verification::queue::QueueInfo as BlockQueueInfo;
|
||||||
use block::{OpenBlock, SealedBlock};
|
use block::{OpenBlock, SealedBlock, ClosedBlock};
|
||||||
use header::{BlockNumber};
|
use header::{BlockNumber};
|
||||||
use transaction::{LocalizedTransaction, PendingTransaction, SignedTransaction};
|
use transaction::{LocalizedTransaction, PendingTransaction, SignedTransaction};
|
||||||
use transaction_import::TransactionImportResult;
|
use transaction_import::TransactionImportResult;
|
||||||
@ -288,6 +288,9 @@ pub trait MiningBlockChainClient: BlockChainClient {
|
|||||||
extra_data: Bytes
|
extra_data: Bytes
|
||||||
) -> OpenBlock;
|
) -> OpenBlock;
|
||||||
|
|
||||||
|
/// Reopens an OpenBlock and updates uncles.
|
||||||
|
fn reopen_block(&self, block: ClosedBlock) -> OpenBlock;
|
||||||
|
|
||||||
/// Returns EvmFactory.
|
/// Returns EvmFactory.
|
||||||
fn vm_factory(&self) -> &EvmFactory;
|
fn vm_factory(&self) -> &EvmFactory;
|
||||||
|
|
||||||
|
@ -266,7 +266,7 @@ mod tests {
|
|||||||
/// Create a new test chain spec with `BasicAuthority` consensus engine.
|
/// Create a new test chain spec with `BasicAuthority` consensus engine.
|
||||||
fn new_test_authority() -> Spec {
|
fn new_test_authority() -> Spec {
|
||||||
let bytes: &[u8] = include_bytes!("../../res/basic_authority.json");
|
let bytes: &[u8] = include_bytes!("../../res/basic_authority.json");
|
||||||
Spec::load(bytes).expect("invalid chain spec")
|
Spec::load(::std::env::temp_dir(), bytes).expect("invalid chain spec")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -376,6 +376,11 @@ pub trait Engine : Sync + Send {
|
|||||||
self.snapshot_components().is_some()
|
self.snapshot_components().is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If this engine supports wasm contracts.
|
||||||
|
fn supports_wasm(&self) -> bool {
|
||||||
|
self.params().wasm
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns new contract address generation scheme at given block number.
|
/// Returns new contract address generation scheme at given block number.
|
||||||
fn create_address_scheme(&self, number: BlockNumber) -> CreateContractAddress {
|
fn create_address_scheme(&self, number: BlockNumber) -> CreateContractAddress {
|
||||||
if number >= self.params().eip86_transition {
|
if number >= self.params().eip86_transition {
|
||||||
@ -386,7 +391,6 @@ pub trait Engine : Sync + Send {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Common engine utilities
|
/// Common engine utilities
|
||||||
pub mod common {
|
pub mod common {
|
||||||
use block::ExecutedBlock;
|
use block::ExecutedBlock;
|
||||||
|
@ -129,6 +129,8 @@ pub enum BlockError {
|
|||||||
UncleIsBrother(OutOfBounds<BlockNumber>),
|
UncleIsBrother(OutOfBounds<BlockNumber>),
|
||||||
/// An uncle is already in the chain.
|
/// An uncle is already in the chain.
|
||||||
UncleInChain(H256),
|
UncleInChain(H256),
|
||||||
|
/// An uncle is included twice.
|
||||||
|
DuplicateUncle(H256),
|
||||||
/// An uncle has a parent not in the chain.
|
/// An uncle has a parent not in the chain.
|
||||||
UncleParentNotInChain(H256),
|
UncleParentNotInChain(H256),
|
||||||
/// State root header field is invalid.
|
/// State root header field is invalid.
|
||||||
@ -188,6 +190,7 @@ impl fmt::Display for BlockError {
|
|||||||
UncleTooOld(ref oob) => format!("Uncle block is too old. {}", oob),
|
UncleTooOld(ref oob) => format!("Uncle block is too old. {}", oob),
|
||||||
UncleIsBrother(ref oob) => format!("Uncle from same generation as block. {}", oob),
|
UncleIsBrother(ref oob) => format!("Uncle from same generation as block. {}", oob),
|
||||||
UncleInChain(ref hash) => format!("Uncle {} already in chain", hash),
|
UncleInChain(ref hash) => format!("Uncle {} already in chain", hash),
|
||||||
|
DuplicateUncle(ref hash) => format!("Uncle {} already in the header", hash),
|
||||||
UncleParentNotInChain(ref hash) => format!("Uncle {} has a parent not in the chain", hash),
|
UncleParentNotInChain(ref hash) => format!("Uncle {} has a parent not in the chain", hash),
|
||||||
InvalidStateRoot(ref mis) => format!("Invalid state root in header: {}", mis),
|
InvalidStateRoot(ref mis) => format!("Invalid state root in header: {}", mis),
|
||||||
InvalidGasUsed(ref mis) => format!("Invalid gas used in header: {}", mis),
|
InvalidGasUsed(ref mis) => format!("Invalid gas used in header: {}", mis),
|
||||||
|
@ -14,6 +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 std::path::Path;
|
||||||
use ethash::{quick_get_difficulty, slow_get_seedhash, EthashManager};
|
use ethash::{quick_get_difficulty, slow_get_seedhash, EthashManager};
|
||||||
use util::*;
|
use util::*;
|
||||||
use block::*;
|
use block::*;
|
||||||
@ -24,7 +25,7 @@ use header::{Header, BlockNumber};
|
|||||||
use state::CleanupMode;
|
use state::CleanupMode;
|
||||||
use spec::CommonParams;
|
use spec::CommonParams;
|
||||||
use transaction::UnverifiedTransaction;
|
use transaction::UnverifiedTransaction;
|
||||||
use engines::Engine;
|
use engines::{self, Engine};
|
||||||
use evm::Schedule;
|
use evm::Schedule;
|
||||||
use ethjson;
|
use ethjson;
|
||||||
use rlp::{self, UntrustedRlp};
|
use rlp::{self, UntrustedRlp};
|
||||||
@ -147,12 +148,17 @@ pub struct Ethash {
|
|||||||
|
|
||||||
impl Ethash {
|
impl Ethash {
|
||||||
/// Create a new instance of Ethash engine
|
/// Create a new instance of Ethash engine
|
||||||
pub fn new(params: CommonParams, ethash_params: EthashParams, builtins: BTreeMap<Address, Builtin>) -> Arc<Self> {
|
pub fn new<T: AsRef<Path>>(
|
||||||
|
cache_dir: T,
|
||||||
|
params: CommonParams,
|
||||||
|
ethash_params: EthashParams,
|
||||||
|
builtins: BTreeMap<Address, Builtin>,
|
||||||
|
) -> Arc<Self> {
|
||||||
Arc::new(Ethash {
|
Arc::new(Ethash {
|
||||||
params: params,
|
params,
|
||||||
ethash_params: ethash_params,
|
ethash_params,
|
||||||
builtins: builtins,
|
builtins,
|
||||||
pow: EthashManager::new(),
|
pow: EthashManager::new(cache_dir),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,7 +171,7 @@ impl Ethash {
|
|||||||
// for any block in the chain.
|
// for any block in the chain.
|
||||||
// in the future, we might move the Ethash epoch
|
// in the future, we might move the Ethash epoch
|
||||||
// caching onto this mechanism as well.
|
// caching onto this mechanism as well.
|
||||||
impl ::engines::EpochVerifier for Arc<Ethash> {
|
impl engines::EpochVerifier for Arc<Ethash> {
|
||||||
fn verify_light(&self, _header: &Header) -> Result<(), Error> { Ok(()) }
|
fn verify_light(&self, _header: &Header) -> Result<(), Error> { Ok(()) }
|
||||||
fn verify_heavy(&self, header: &Header) -> Result<(), Error> {
|
fn verify_heavy(&self, header: &Header) -> Result<(), Error> {
|
||||||
self.verify_block_unordered(header, None)
|
self.verify_block_unordered(header, None)
|
||||||
@ -262,7 +268,7 @@ impl Engine for Arc<Ethash> {
|
|||||||
_begins_epoch: bool,
|
_begins_epoch: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let parent_hash = block.fields().header.parent_hash().clone();
|
let parent_hash = block.fields().header.parent_hash().clone();
|
||||||
::engines::common::push_last_hash(block, last_hashes, self, &parent_hash)?;
|
engines::common::push_last_hash(block, last_hashes, self, &parent_hash)?;
|
||||||
if block.fields().header.number() == self.ethash_params.dao_hardfork_transition {
|
if block.fields().header.number() == self.ethash_params.dao_hardfork_transition {
|
||||||
let state = block.fields_mut().state;
|
let state = block.fields_mut().state;
|
||||||
for child in &self.ethash_params.dao_hardfork_accounts {
|
for child in &self.ethash_params.dao_hardfork_accounts {
|
||||||
@ -404,8 +410,8 @@ impl Engine for Arc<Ethash> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn epoch_verifier<'a>(&self, _header: &Header, _proof: &'a [u8]) -> ::engines::ConstructedVerifier<'a> {
|
fn epoch_verifier<'a>(&self, _header: &Header, _proof: &'a [u8]) -> engines::ConstructedVerifier<'a> {
|
||||||
::engines::ConstructedVerifier::Trusted(Box::new(self.clone()))
|
engines::ConstructedVerifier::Trusted(Box::new(self.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn snapshot_components(&self) -> Option<Box<::snapshot::SnapshotComponents>> {
|
fn snapshot_components(&self) -> Option<Box<::snapshot::SnapshotComponents>> {
|
||||||
@ -558,13 +564,18 @@ mod tests {
|
|||||||
use engines::Engine;
|
use engines::Engine;
|
||||||
use error::{BlockError, Error};
|
use error::{BlockError, Error};
|
||||||
use header::Header;
|
use header::Header;
|
||||||
|
use spec::Spec;
|
||||||
use super::super::{new_morden, new_homestead_test};
|
use super::super::{new_morden, new_homestead_test};
|
||||||
use super::{Ethash, EthashParams, PARITY_GAS_LIMIT_DETERMINANT, ecip1017_eras_block_reward};
|
use super::{Ethash, EthashParams, PARITY_GAS_LIMIT_DETERMINANT, ecip1017_eras_block_reward};
|
||||||
use rlp;
|
use rlp;
|
||||||
|
|
||||||
|
fn test_spec() -> Spec {
|
||||||
|
new_morden(&::std::env::temp_dir())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn on_close_block() {
|
fn on_close_block() {
|
||||||
let spec = new_morden();
|
let spec = test_spec();
|
||||||
let engine = &*spec.engine;
|
let engine = &*spec.engine;
|
||||||
let genesis_header = spec.genesis_header();
|
let genesis_header = spec.genesis_header();
|
||||||
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
||||||
@ -576,7 +587,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn on_close_block_with_uncle() {
|
fn on_close_block_with_uncle() {
|
||||||
let spec = new_morden();
|
let spec = test_spec();
|
||||||
let engine = &*spec.engine;
|
let engine = &*spec.engine;
|
||||||
let genesis_header = spec.genesis_header();
|
let genesis_header = spec.genesis_header();
|
||||||
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
||||||
@ -594,14 +605,14 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn has_valid_metadata() {
|
fn has_valid_metadata() {
|
||||||
let engine = new_morden().engine;
|
let engine = test_spec().engine;
|
||||||
assert!(!engine.name().is_empty());
|
assert!(!engine.name().is_empty());
|
||||||
assert!(engine.version().major >= 1);
|
assert!(engine.version().major >= 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_return_schedule() {
|
fn can_return_schedule() {
|
||||||
let engine = new_morden().engine;
|
let engine = test_spec().engine;
|
||||||
let schedule = engine.schedule(10000000);
|
let schedule = engine.schedule(10000000);
|
||||||
assert!(schedule.stack_limit > 0);
|
assert!(schedule.stack_limit > 0);
|
||||||
|
|
||||||
@ -611,8 +622,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_do_seal_verification_fail() {
|
fn can_do_seal_verification_fail() {
|
||||||
let engine = new_morden().engine;
|
let engine = test_spec().engine;
|
||||||
//let engine = Ethash::new_test(new_morden());
|
//let engine = Ethash::new_test(test_spec());
|
||||||
let header: Header = Header::default();
|
let header: Header = Header::default();
|
||||||
|
|
||||||
let verify_result = engine.verify_block_basic(&header, None);
|
let verify_result = engine.verify_block_basic(&header, None);
|
||||||
@ -626,7 +637,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_do_difficulty_verification_fail() {
|
fn can_do_difficulty_verification_fail() {
|
||||||
let engine = new_morden().engine;
|
let engine = test_spec().engine;
|
||||||
let mut header: Header = Header::default();
|
let mut header: Header = Header::default();
|
||||||
header.set_seal(vec![rlp::encode(&H256::zero()).into_vec(), rlp::encode(&H64::zero()).into_vec()]);
|
header.set_seal(vec![rlp::encode(&H256::zero()).into_vec(), rlp::encode(&H64::zero()).into_vec()]);
|
||||||
|
|
||||||
@ -641,7 +652,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_do_proof_of_work_verification_fail() {
|
fn can_do_proof_of_work_verification_fail() {
|
||||||
let engine = new_morden().engine;
|
let engine = test_spec().engine;
|
||||||
let mut header: Header = Header::default();
|
let mut header: Header = Header::default();
|
||||||
header.set_seal(vec![rlp::encode(&H256::zero()).into_vec(), rlp::encode(&H64::zero()).into_vec()]);
|
header.set_seal(vec![rlp::encode(&H256::zero()).into_vec(), rlp::encode(&H64::zero()).into_vec()]);
|
||||||
header.set_difficulty(U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaa").unwrap());
|
header.set_difficulty(U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaa").unwrap());
|
||||||
@ -657,7 +668,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_do_seal_unordered_verification_fail() {
|
fn can_do_seal_unordered_verification_fail() {
|
||||||
let engine = new_morden().engine;
|
let engine = test_spec().engine;
|
||||||
let header: Header = Header::default();
|
let header: Header = Header::default();
|
||||||
|
|
||||||
let verify_result = engine.verify_block_unordered(&header, None);
|
let verify_result = engine.verify_block_unordered(&header, None);
|
||||||
@ -671,7 +682,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_do_seal256_verification_fail() {
|
fn can_do_seal256_verification_fail() {
|
||||||
let engine = new_morden().engine;
|
let engine = test_spec().engine;
|
||||||
let mut header: Header = Header::default();
|
let mut header: Header = Header::default();
|
||||||
header.set_seal(vec![rlp::encode(&H256::zero()).into_vec(), rlp::encode(&H64::zero()).into_vec()]);
|
header.set_seal(vec![rlp::encode(&H256::zero()).into_vec(), rlp::encode(&H64::zero()).into_vec()]);
|
||||||
let verify_result = engine.verify_block_unordered(&header, None);
|
let verify_result = engine.verify_block_unordered(&header, None);
|
||||||
@ -685,7 +696,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_do_proof_of_work_unordered_verification_fail() {
|
fn can_do_proof_of_work_unordered_verification_fail() {
|
||||||
let engine = new_morden().engine;
|
let engine = test_spec().engine;
|
||||||
let mut header: Header = Header::default();
|
let mut header: Header = Header::default();
|
||||||
header.set_seal(vec![rlp::encode(&H256::from("b251bd2e0283d0658f2cadfdc8ca619b5de94eca5742725e2e757dd13ed7503d")).into_vec(), rlp::encode(&H64::zero()).into_vec()]);
|
header.set_seal(vec![rlp::encode(&H256::from("b251bd2e0283d0658f2cadfdc8ca619b5de94eca5742725e2e757dd13ed7503d")).into_vec(), rlp::encode(&H64::zero()).into_vec()]);
|
||||||
header.set_difficulty(U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaa").unwrap());
|
header.set_difficulty(U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaa").unwrap());
|
||||||
@ -701,7 +712,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_verify_block_family_genesis_fail() {
|
fn can_verify_block_family_genesis_fail() {
|
||||||
let engine = new_morden().engine;
|
let engine = test_spec().engine;
|
||||||
let header: Header = Header::default();
|
let header: Header = Header::default();
|
||||||
let parent_header: Header = Header::default();
|
let parent_header: Header = Header::default();
|
||||||
|
|
||||||
@ -716,7 +727,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_verify_block_family_difficulty_fail() {
|
fn can_verify_block_family_difficulty_fail() {
|
||||||
let engine = new_morden().engine;
|
let engine = test_spec().engine;
|
||||||
let mut header: Header = Header::default();
|
let mut header: Header = Header::default();
|
||||||
header.set_number(2);
|
header.set_number(2);
|
||||||
let mut parent_header: Header = Header::default();
|
let mut parent_header: Header = Header::default();
|
||||||
@ -733,7 +744,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_verify_block_family_gas_fail() {
|
fn can_verify_block_family_gas_fail() {
|
||||||
let engine = new_morden().engine;
|
let engine = test_spec().engine;
|
||||||
let mut header: Header = Header::default();
|
let mut header: Header = Header::default();
|
||||||
header.set_number(2);
|
header.set_number(2);
|
||||||
header.set_difficulty(U256::from_str("0000000000000000000000000000000000000000000000000000000000020000").unwrap());
|
header.set_difficulty(U256::from_str("0000000000000000000000000000000000000000000000000000000000020000").unwrap());
|
||||||
@ -763,7 +774,7 @@ mod tests {
|
|||||||
fn difficulty_frontier() {
|
fn difficulty_frontier() {
|
||||||
let spec = new_homestead_test();
|
let spec = new_homestead_test();
|
||||||
let ethparams = get_default_ethash_params();
|
let ethparams = get_default_ethash_params();
|
||||||
let ethash = Ethash::new(spec.params().clone(), ethparams, BTreeMap::new());
|
let ethash = Ethash::new(&::std::env::temp_dir(), spec.params().clone(), ethparams, BTreeMap::new());
|
||||||
|
|
||||||
let mut parent_header = Header::default();
|
let mut parent_header = Header::default();
|
||||||
parent_header.set_number(1000000);
|
parent_header.set_number(1000000);
|
||||||
@ -781,7 +792,7 @@ mod tests {
|
|||||||
fn difficulty_homestead() {
|
fn difficulty_homestead() {
|
||||||
let spec = new_homestead_test();
|
let spec = new_homestead_test();
|
||||||
let ethparams = get_default_ethash_params();
|
let ethparams = get_default_ethash_params();
|
||||||
let ethash = Ethash::new(spec.params().clone(), ethparams, BTreeMap::new());
|
let ethash = Ethash::new(&::std::env::temp_dir(), spec.params().clone(), ethparams, BTreeMap::new());
|
||||||
|
|
||||||
let mut parent_header = Header::default();
|
let mut parent_header = Header::default();
|
||||||
parent_header.set_number(1500000);
|
parent_header.set_number(1500000);
|
||||||
@ -838,7 +849,7 @@ mod tests {
|
|||||||
ecip1010_pause_transition: 3000000,
|
ecip1010_pause_transition: 3000000,
|
||||||
..get_default_ethash_params()
|
..get_default_ethash_params()
|
||||||
};
|
};
|
||||||
let ethash = Ethash::new(spec.params().clone(), ethparams, BTreeMap::new());
|
let ethash = Ethash::new(&::std::env::temp_dir(), spec.params().clone(), ethparams, BTreeMap::new());
|
||||||
|
|
||||||
let mut parent_header = Header::default();
|
let mut parent_header = Header::default();
|
||||||
parent_header.set_number(3500000);
|
parent_header.set_number(3500000);
|
||||||
@ -872,7 +883,7 @@ mod tests {
|
|||||||
ecip1010_continue_transition: 5000000,
|
ecip1010_continue_transition: 5000000,
|
||||||
..get_default_ethash_params()
|
..get_default_ethash_params()
|
||||||
};
|
};
|
||||||
let ethash = Ethash::new(spec.params().clone(), ethparams, BTreeMap::new());
|
let ethash = Ethash::new(&::std::env::temp_dir(), spec.params().clone(), ethparams, BTreeMap::new());
|
||||||
|
|
||||||
let mut parent_header = Header::default();
|
let mut parent_header = Header::default();
|
||||||
parent_header.set_number(5000102);
|
parent_header.set_number(5000102);
|
||||||
@ -917,7 +928,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn gas_limit_is_multiple_of_determinant() {
|
fn gas_limit_is_multiple_of_determinant() {
|
||||||
let spec = new_homestead_test();
|
let spec = new_homestead_test();
|
||||||
let ethash = Ethash::new(spec.params().clone(), get_default_ethash_params(), BTreeMap::new());
|
let ethparams = get_default_ethash_params();
|
||||||
|
let ethash = Ethash::new(&::std::env::temp_dir(), spec.params().clone(), ethparams, BTreeMap::new());
|
||||||
let mut parent = Header::new();
|
let mut parent = Header::new();
|
||||||
let mut header = Header::new();
|
let mut header = Header::new();
|
||||||
header.set_number(1);
|
header.set_number(1);
|
||||||
@ -961,7 +973,7 @@ mod tests {
|
|||||||
fn difficulty_max_timestamp() {
|
fn difficulty_max_timestamp() {
|
||||||
let spec = new_homestead_test();
|
let spec = new_homestead_test();
|
||||||
let ethparams = get_default_ethash_params();
|
let ethparams = get_default_ethash_params();
|
||||||
let ethash = Ethash::new(spec.params().clone(), ethparams, BTreeMap::new());
|
let ethash = Ethash::new(&::std::env::temp_dir(), spec.params().clone(), ethparams, BTreeMap::new());
|
||||||
|
|
||||||
let mut parent_header = Header::default();
|
let mut parent_header = Header::default();
|
||||||
parent_header.set_number(1000000);
|
parent_header.set_number(1000000);
|
||||||
@ -989,7 +1001,7 @@ mod tests {
|
|||||||
header.set_number(parent_header.number() + 1);
|
header.set_number(parent_header.number() + 1);
|
||||||
header.set_gas_limit(100_001.into());
|
header.set_gas_limit(100_001.into());
|
||||||
header.set_difficulty(ethparams.minimum_difficulty);
|
header.set_difficulty(ethparams.minimum_difficulty);
|
||||||
let ethash = Ethash::new(spec.params().clone(), ethparams, BTreeMap::new());
|
let ethash = Ethash::new(&::std::env::temp_dir(), spec.params().clone(), ethparams, BTreeMap::new());
|
||||||
assert!(ethash.verify_block_family(&header, &parent_header, None).is_ok());
|
assert!(ethash.verify_block_family(&header, &parent_header, None).is_ok());
|
||||||
|
|
||||||
parent_header.set_number(9);
|
parent_header.set_number(9);
|
||||||
@ -1044,7 +1056,7 @@ mod tests {
|
|||||||
nonce: U256::zero(),
|
nonce: U256::zero(),
|
||||||
}.sign(keypair.secret(), None).into();
|
}.sign(keypair.secret(), None).into();
|
||||||
|
|
||||||
let ethash = Ethash::new(spec.params().clone(), ethparams, BTreeMap::new());
|
let ethash = Ethash::new(&::std::env::temp_dir(), spec.params().clone(), ethparams, BTreeMap::new());
|
||||||
assert!(ethash.verify_transaction_basic(&tx1, &header).is_ok());
|
assert!(ethash.verify_transaction_basic(&tx1, &header).is_ok());
|
||||||
assert!(ethash.verify_transaction_basic(&tx2, &header).is_ok());
|
assert!(ethash.verify_transaction_basic(&tx2, &header).is_ok());
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ pub mod denominations;
|
|||||||
pub use self::ethash::{Ethash};
|
pub use self::ethash::{Ethash};
|
||||||
pub use self::denominations::*;
|
pub use self::denominations::*;
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
use super::spec::*;
|
use super::spec::*;
|
||||||
|
|
||||||
/// Most recent fork block that we support on Mainnet.
|
/// Most recent fork block that we support on Mainnet.
|
||||||
@ -38,51 +39,56 @@ pub const FORK_SUPPORTED_ROPSTEN: u64 = 10;
|
|||||||
/// Most recent fork block that we support on Kovan.
|
/// Most recent fork block that we support on Kovan.
|
||||||
pub const FORK_SUPPORTED_KOVAN: u64 = 0;
|
pub const FORK_SUPPORTED_KOVAN: u64 = 0;
|
||||||
|
|
||||||
fn load(b: &[u8]) -> Spec {
|
fn load<'a, T: 'a + Into<Option<&'a Path>>>(cache_dir: T, b: &[u8]) -> Spec {
|
||||||
Spec::load(b).expect("chain spec is invalid")
|
match cache_dir.into() {
|
||||||
|
Some(path) => Spec::load(path, b),
|
||||||
|
None => Spec::load(&::std::env::temp_dir(), b)
|
||||||
|
}.expect("chain spec is invalid")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new Foundation Olympic chain spec.
|
/// Create a new Foundation Olympic chain spec.
|
||||||
pub fn new_olympic() -> Spec { load(include_bytes!("../../res/ethereum/olympic.json")) }
|
pub fn new_olympic(cache_dir: &Path) -> Spec { load(cache_dir, include_bytes!("../../res/ethereum/olympic.json")) }
|
||||||
|
|
||||||
/// Create a new Foundation Mainnet chain spec.
|
/// Create a new Foundation Mainnet chain spec.
|
||||||
pub fn new_foundation() -> Spec { load(include_bytes!("../../res/ethereum/foundation.json")) }
|
pub fn new_foundation(cache_dir: &Path) -> Spec { load(cache_dir, include_bytes!("../../res/ethereum/foundation.json")) }
|
||||||
|
|
||||||
/// Create a new Classic Mainnet chain spec without the DAO hardfork.
|
/// Create a new Classic Mainnet chain spec without the DAO hardfork.
|
||||||
pub fn new_classic() -> Spec { load(include_bytes!("../../res/ethereum/classic.json")) }
|
pub fn new_classic(cache_dir: &Path) -> Spec { load(cache_dir, include_bytes!("../../res/ethereum/classic.json")) }
|
||||||
|
|
||||||
/// Create a new Expanse mainnet chain spec.
|
/// Create a new Expanse mainnet chain spec.
|
||||||
pub fn new_expanse() -> Spec { load(include_bytes!("../../res/ethereum/expanse.json")) }
|
pub fn new_expanse(cache_dir: &Path) -> Spec { load(cache_dir, include_bytes!("../../res/ethereum/expanse.json")) }
|
||||||
|
|
||||||
/// Create a new Kovan testnet chain spec.
|
/// Create a new Kovan testnet chain spec.
|
||||||
pub fn new_kovan() -> Spec { load(include_bytes!("../../res/ethereum/kovan.json")) }
|
pub fn new_kovan(cache_dir: &Path) -> Spec { load(cache_dir, include_bytes!("../../res/ethereum/kovan.json")) }
|
||||||
|
|
||||||
/// Create a new Foundation Frontier-era chain spec as though it never changes to Homestead.
|
|
||||||
pub fn new_frontier_test() -> Spec { load(include_bytes!("../../res/ethereum/frontier_test.json")) }
|
|
||||||
|
|
||||||
/// Create a new Foundation Homestead-era chain spec as though it never changed from Frontier.
|
|
||||||
pub fn new_homestead_test() -> Spec { load(include_bytes!("../../res/ethereum/homestead_test.json")) }
|
|
||||||
|
|
||||||
/// Create a new Foundation Homestead-EIP150-era chain spec as though it never changed from Homestead/Frontier.
|
|
||||||
pub fn new_eip150_test() -> Spec { load(include_bytes!("../../res/ethereum/eip150_test.json")) }
|
|
||||||
|
|
||||||
/// Create a new Foundation Homestead-EIP161-era chain spec as though it never changed from Homestead/Frontier.
|
|
||||||
pub fn new_eip161_test() -> Spec { load(include_bytes!("../../res/ethereum/eip161_test.json")) }
|
|
||||||
|
|
||||||
/// Create a new Foundation Frontier/Homestead/DAO chain spec with transition points at #5 and #8.
|
|
||||||
pub fn new_transition_test() -> Spec { load(include_bytes!("../../res/ethereum/transition_test.json")) }
|
|
||||||
|
|
||||||
/// Create a new Foundation Mainnet chain spec without genesis accounts.
|
|
||||||
pub fn new_mainnet_like() -> Spec { load(include_bytes!("../../res/ethereum/frontier_like_test.json")) }
|
|
||||||
|
|
||||||
/// Create a new Foundation Metropolis era spec.
|
|
||||||
pub fn new_metropolis_test() -> Spec { load(include_bytes!("../../res/ethereum/metropolis_test.json")) }
|
|
||||||
|
|
||||||
/// Create a new Foundation Ropsten chain spec.
|
/// Create a new Foundation Ropsten chain spec.
|
||||||
pub fn new_ropsten() -> Spec { load(include_bytes!("../../res/ethereum/ropsten.json")) }
|
pub fn new_ropsten(cache_dir: &Path) -> Spec { load(cache_dir, include_bytes!("../../res/ethereum/ropsten.json")) }
|
||||||
|
|
||||||
/// Create a new Morden chain spec.
|
/// Create a new Morden chain spec.
|
||||||
pub fn new_morden() -> Spec { load(include_bytes!("../../res/ethereum/morden.json")) }
|
pub fn new_morden(cache_dir: &Path) -> Spec { load(cache_dir, include_bytes!("../../res/ethereum/morden.json")) }
|
||||||
|
|
||||||
|
// For tests
|
||||||
|
|
||||||
|
/// Create a new Foundation Frontier-era chain spec as though it never changes to Homestead.
|
||||||
|
pub fn new_frontier_test() -> Spec { load(None, include_bytes!("../../res/ethereum/frontier_test.json")) }
|
||||||
|
|
||||||
|
/// Create a new Foundation Homestead-era chain spec as though it never changed from Frontier.
|
||||||
|
pub fn new_homestead_test() -> Spec { load(None, include_bytes!("../../res/ethereum/homestead_test.json")) }
|
||||||
|
|
||||||
|
/// Create a new Foundation Homestead-EIP150-era chain spec as though it never changed from Homestead/Frontier.
|
||||||
|
pub fn new_eip150_test() -> Spec { load(None, include_bytes!("../../res/ethereum/eip150_test.json")) }
|
||||||
|
|
||||||
|
/// Create a new Foundation Homestead-EIP161-era chain spec as though it never changed from Homestead/Frontier.
|
||||||
|
pub fn new_eip161_test() -> Spec { load(None, include_bytes!("../../res/ethereum/eip161_test.json")) }
|
||||||
|
|
||||||
|
/// Create a new Foundation Frontier/Homestead/DAO chain spec with transition points at #5 and #8.
|
||||||
|
pub fn new_transition_test() -> Spec { load(None, include_bytes!("../../res/ethereum/transition_test.json")) }
|
||||||
|
|
||||||
|
/// Create a new Foundation Mainnet chain spec without genesis accounts.
|
||||||
|
pub fn new_mainnet_like() -> Spec { load(None, include_bytes!("../../res/ethereum/frontier_like_test.json")) }
|
||||||
|
|
||||||
|
/// Create a new Foundation Metropolis era spec.
|
||||||
|
pub fn new_metropolis_test() -> Spec { load(None, include_bytes!("../../res/ethereum/metropolis_test.json")) }
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
@ -94,7 +100,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ensure_db_good() {
|
fn ensure_db_good() {
|
||||||
let spec = new_morden();
|
let spec = new_morden(&::std::env::temp_dir());
|
||||||
let engine = &spec.engine;
|
let engine = &spec.engine;
|
||||||
let genesis_header = spec.genesis_header();
|
let genesis_header = spec.genesis_header();
|
||||||
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
||||||
@ -109,7 +115,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn morden() {
|
fn morden() {
|
||||||
let morden = new_morden();
|
let morden = new_morden(&::std::env::temp_dir());
|
||||||
|
|
||||||
assert_eq!(morden.state_root(), "f3f4696bbf3b3b07775128eb7a3763279a394e382130f27c21e70233e04946a9".into());
|
assert_eq!(morden.state_root(), "f3f4696bbf3b3b07775128eb7a3763279a394e382130f27c21e70233e04946a9".into());
|
||||||
let genesis = morden.genesis_block();
|
let genesis = morden.genesis_block();
|
||||||
@ -120,7 +126,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn frontier() {
|
fn frontier() {
|
||||||
let frontier = new_foundation();
|
let frontier = new_foundation(&::std::env::temp_dir());
|
||||||
|
|
||||||
assert_eq!(frontier.state_root(), "d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544".into());
|
assert_eq!(frontier.state_root(), "d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544".into());
|
||||||
let genesis = frontier.genesis_block();
|
let genesis = frontier.genesis_block();
|
||||||
@ -128,4 +134,23 @@ mod tests {
|
|||||||
|
|
||||||
let _ = frontier.engine;
|
let _ = frontier.engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn all_spec_files_valid() {
|
||||||
|
let tmp = ::std::env::temp_dir();
|
||||||
|
new_olympic(&tmp);
|
||||||
|
new_foundation(&tmp);
|
||||||
|
new_classic(&tmp);
|
||||||
|
new_expanse(&tmp);
|
||||||
|
new_kovan(&tmp);
|
||||||
|
new_ropsten(&tmp);
|
||||||
|
new_morden(&tmp);
|
||||||
|
new_frontier_test();
|
||||||
|
new_homestead_test();
|
||||||
|
new_eip150_test();
|
||||||
|
new_eip161_test();
|
||||||
|
new_transition_test();
|
||||||
|
new_mainnet_like();
|
||||||
|
new_metropolis_test();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ use util::{U128, U256, U512, trie};
|
|||||||
use action_params::ActionParams;
|
use action_params::ActionParams;
|
||||||
use evm::Ext;
|
use evm::Ext;
|
||||||
use builtin;
|
use builtin;
|
||||||
|
use super::wasm;
|
||||||
|
|
||||||
/// Evm errors.
|
/// Evm errors.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
@ -66,6 +67,8 @@ pub enum Error {
|
|||||||
MutableCallInStaticContext,
|
MutableCallInStaticContext,
|
||||||
/// Likely to cause consensus issues.
|
/// Likely to cause consensus issues.
|
||||||
Internal(String),
|
Internal(String),
|
||||||
|
/// Wasm runtime error
|
||||||
|
Wasm(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Box<trie::TrieError>> for Error {
|
impl From<Box<trie::TrieError>> for Error {
|
||||||
@ -80,6 +83,12 @@ impl From<builtin::Error> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<wasm::RuntimeError> for Error {
|
||||||
|
fn from(err: wasm::RuntimeError) -> Self {
|
||||||
|
Error::Wasm(format!("Runtime error: {:?}", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
use self::Error::*;
|
use self::Error::*;
|
||||||
@ -92,6 +101,7 @@ impl fmt::Display for Error {
|
|||||||
BuiltIn(name) => write!(f, "Built-in failed: {}", name),
|
BuiltIn(name) => write!(f, "Built-in failed: {}", name),
|
||||||
Internal(ref msg) => write!(f, "Internal error: {}", msg),
|
Internal(ref msg) => write!(f, "Internal error: {}", msg),
|
||||||
MutableCallInStaticContext => write!(f, "Mutable call in static context"),
|
MutableCallInStaticContext => write!(f, "Mutable call in static context"),
|
||||||
|
Wasm(ref msg) => write!(f, "Internal error: {}", msg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,8 +129,11 @@ pub trait Ext {
|
|||||||
/// Increments sstore refunds count by 1.
|
/// Increments sstore refunds count by 1.
|
||||||
fn inc_sstore_clears(&mut self);
|
fn inc_sstore_clears(&mut self);
|
||||||
|
|
||||||
|
/// Decide if any more operations should be traced. Passthrough for the VM trace.
|
||||||
|
fn trace_next_instruction(&mut self, _pc: usize, _instruction: u8) -> bool { false }
|
||||||
|
|
||||||
/// Prepare to trace an operation. Passthrough for the VM trace.
|
/// Prepare to trace an operation. Passthrough for the VM trace.
|
||||||
fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _gas_cost: &U256) -> bool { false }
|
fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _gas_cost: U256) {}
|
||||||
|
|
||||||
/// Trace the finalised execution of a single instruction.
|
/// Trace the finalised execution of a single instruction.
|
||||||
fn trace_executed(&mut self, _gas_used: U256, _stack_push: &[U256], _mem_diff: Option<(usize, &[u8])>, _store_diff: Option<(U256, U256)>) {}
|
fn trace_executed(&mut self, _gas_used: U256, _stack_push: &[U256], _mem_diff: Option<(usize, &[u8])>, _store_diff: Option<(U256, U256)>) {}
|
||||||
|
@ -111,6 +111,7 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
|
|||||||
self.mem.clear();
|
self.mem.clear();
|
||||||
|
|
||||||
let mut informant = informant::EvmInformant::new(ext.depth());
|
let mut informant = informant::EvmInformant::new(ext.depth());
|
||||||
|
let mut do_trace = true;
|
||||||
|
|
||||||
let code = ¶ms.code.as_ref().expect("exec always called with code; qed");
|
let code = ¶ms.code.as_ref().expect("exec always called with code; qed");
|
||||||
let mut valid_jump_destinations = None;
|
let mut valid_jump_destinations = None;
|
||||||
@ -124,13 +125,17 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
|
|||||||
let instruction = code[reader.position];
|
let instruction = code[reader.position];
|
||||||
reader.position += 1;
|
reader.position += 1;
|
||||||
|
|
||||||
|
// TODO: make compile-time removable if too much of a performance hit.
|
||||||
|
do_trace = do_trace && ext.trace_next_instruction(reader.position - 1, instruction);
|
||||||
|
|
||||||
let info = &infos[instruction as usize];
|
let info = &infos[instruction as usize];
|
||||||
self.verify_instruction(ext, instruction, info, &stack)?;
|
self.verify_instruction(ext, instruction, info, &stack)?;
|
||||||
|
|
||||||
// Calculate gas cost
|
// Calculate gas cost
|
||||||
let requirements = gasometer.requirements(ext, instruction, info, &stack, self.mem.size())?;
|
let requirements = gasometer.requirements(ext, instruction, info, &stack, self.mem.size())?;
|
||||||
// TODO: make compile-time removable if too much of a performance hit.
|
if do_trace {
|
||||||
let trace_executed = ext.trace_prepare_execute(reader.position - 1, instruction, &requirements.gas_cost.as_u256());
|
ext.trace_prepare_execute(reader.position - 1, instruction, requirements.gas_cost.as_u256());
|
||||||
|
}
|
||||||
|
|
||||||
gasometer.verify_gas(&requirements.gas_cost)?;
|
gasometer.verify_gas(&requirements.gas_cost)?;
|
||||||
self.mem.expand(requirements.memory_required_size);
|
self.mem.expand(requirements.memory_required_size);
|
||||||
@ -139,7 +144,7 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
|
|||||||
|
|
||||||
evm_debug!({ informant.before_instruction(reader.position, instruction, info, &gasometer.current_gas, &stack) });
|
evm_debug!({ informant.before_instruction(reader.position, instruction, info, &gasometer.current_gas, &stack) });
|
||||||
|
|
||||||
let (mem_written, store_written) = match trace_executed {
|
let (mem_written, store_written) = match do_trace {
|
||||||
true => (Self::mem_written(instruction, &stack), Self::store_written(instruction, &stack)),
|
true => (Self::mem_written(instruction, &stack), Self::store_written(instruction, &stack)),
|
||||||
false => (None, None),
|
false => (None, None),
|
||||||
};
|
};
|
||||||
@ -155,7 +160,7 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
|
|||||||
gasometer.current_gas = gasometer.current_gas + *gas;
|
gasometer.current_gas = gasometer.current_gas + *gas;
|
||||||
}
|
}
|
||||||
|
|
||||||
if trace_executed {
|
if do_trace {
|
||||||
ext.trace_executed(gasometer.current_gas.as_u256(), stack.peek_top(info.ret), mem_written.map(|(o, s)| (o, &(self.mem[o..(o + s)]))), store_written);
|
ext.trace_executed(gasometer.current_gas.as_u256(), stack.peek_top(info.ret), mem_written.map(|(o, s)| (o, &(self.mem[o..(o + s)]))), store_written);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ pub mod interpreter;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod factory;
|
pub mod factory;
|
||||||
pub mod schedule;
|
pub mod schedule;
|
||||||
|
pub mod wasm;
|
||||||
|
|
||||||
mod vmtype;
|
mod vmtype;
|
||||||
mod instructions;
|
mod instructions;
|
||||||
|
@ -39,13 +39,13 @@ pub enum FakeCallType {
|
|||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash, Debug)]
|
#[derive(PartialEq, Eq, Hash, Debug)]
|
||||||
pub struct FakeCall {
|
pub struct FakeCall {
|
||||||
call_type: FakeCallType,
|
pub call_type: FakeCallType,
|
||||||
gas: U256,
|
pub gas: U256,
|
||||||
sender_address: Option<Address>,
|
pub sender_address: Option<Address>,
|
||||||
receive_address: Option<Address>,
|
pub receive_address: Option<Address>,
|
||||||
value: Option<U256>,
|
pub value: Option<U256>,
|
||||||
data: Bytes,
|
pub data: Bytes,
|
||||||
code_address: Option<Address>,
|
pub code_address: Option<Address>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fake externalities test structure.
|
/// Fake externalities test structure.
|
||||||
@ -53,17 +53,17 @@ pub struct FakeCall {
|
|||||||
/// Can't do recursive calls.
|
/// Can't do recursive calls.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct FakeExt {
|
pub struct FakeExt {
|
||||||
|
pub store: HashMap<H256, H256>,
|
||||||
|
pub suicides: HashSet<Address>,
|
||||||
|
pub calls: HashSet<FakeCall>,
|
||||||
sstore_clears: usize,
|
sstore_clears: usize,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
store: HashMap<H256, H256>,
|
|
||||||
blockhashes: HashMap<U256, H256>,
|
blockhashes: HashMap<U256, H256>,
|
||||||
codes: HashMap<Address, Arc<Bytes>>,
|
codes: HashMap<Address, Arc<Bytes>>,
|
||||||
logs: Vec<FakeLogEntry>,
|
logs: Vec<FakeLogEntry>,
|
||||||
_suicides: HashSet<Address>,
|
|
||||||
info: EnvInfo,
|
info: EnvInfo,
|
||||||
schedule: Schedule,
|
schedule: Schedule,
|
||||||
balances: HashMap<Address, U256>,
|
balances: HashMap<Address, U256>,
|
||||||
calls: HashSet<FakeCall>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// similar to the normal `finalize` function, but ignoring NeedsReturn.
|
// similar to the normal `finalize` function, but ignoring NeedsReturn.
|
||||||
@ -173,8 +173,9 @@ impl Ext for FakeExt {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suicide(&mut self, _refund_address: &Address) -> evm::Result<()> {
|
fn suicide(&mut self, refund_address: &Address) -> evm::Result<()> {
|
||||||
unimplemented!();
|
self.suicides.insert(refund_address.clone());
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn schedule(&self) -> &Schedule {
|
fn schedule(&self) -> &Schedule {
|
||||||
|
62
ethcore/src/evm/wasm/call_args.rs
Normal file
62
ethcore/src/evm/wasm/call_args.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
//! Wasm evm call arguments helper
|
||||||
|
|
||||||
|
use util::{U256, H160};
|
||||||
|
|
||||||
|
/// Input part of the wasm call descriptor
|
||||||
|
pub struct CallArgs {
|
||||||
|
/// Receiver of the transaction
|
||||||
|
pub address: [u8; 20],
|
||||||
|
|
||||||
|
/// Sender of the transaction
|
||||||
|
pub sender: [u8; 20],
|
||||||
|
|
||||||
|
/// Original transaction initiator
|
||||||
|
pub origin: [u8; 20],
|
||||||
|
|
||||||
|
/// Transfer value
|
||||||
|
pub value: [u8; 32],
|
||||||
|
|
||||||
|
/// call/create params
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CallArgs {
|
||||||
|
/// New contract call payload with known parameters
|
||||||
|
pub fn new(address: H160, sender: H160, origin: H160, value: U256, data: Vec<u8>) -> Self {
|
||||||
|
let mut descriptor = CallArgs {
|
||||||
|
address: [0u8; 20],
|
||||||
|
sender: [0u8; 20],
|
||||||
|
origin: [0u8; 20],
|
||||||
|
value: [0u8; 32],
|
||||||
|
data: data,
|
||||||
|
};
|
||||||
|
|
||||||
|
descriptor.address.copy_from_slice(&*address);
|
||||||
|
descriptor.sender.copy_from_slice(&*sender);
|
||||||
|
descriptor.origin.copy_from_slice(&*origin);
|
||||||
|
value.to_big_endian(&mut descriptor.value);
|
||||||
|
|
||||||
|
descriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Total call payload length in linear memory
|
||||||
|
pub fn len(&self) -> u32 {
|
||||||
|
self.data.len() as u32 + 92
|
||||||
|
}
|
||||||
|
}
|
119
ethcore/src/evm/wasm/env.rs
Normal file
119
ethcore/src/evm/wasm/env.rs
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
//! Wasm env module bindings
|
||||||
|
|
||||||
|
use parity_wasm::elements::ValueType::*;
|
||||||
|
use parity_wasm::interpreter::UserFunctionDescriptor;
|
||||||
|
use parity_wasm::interpreter::UserFunctionDescriptor::*;
|
||||||
|
|
||||||
|
pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
|
||||||
|
Static(
|
||||||
|
"_storage_read",
|
||||||
|
&[I32; 2],
|
||||||
|
Some(I32),
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"_storage_write",
|
||||||
|
&[I32; 2],
|
||||||
|
Some(I32),
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"_malloc",
|
||||||
|
&[I32],
|
||||||
|
Some(I32),
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"_free",
|
||||||
|
&[I32],
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"gas",
|
||||||
|
&[I32],
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"_debug",
|
||||||
|
&[I32; 2],
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"_suicide",
|
||||||
|
&[I32],
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"_create",
|
||||||
|
&[I32; 4],
|
||||||
|
Some(I32),
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"abort",
|
||||||
|
&[I32],
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"_abort",
|
||||||
|
&[],
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"invoke_vii",
|
||||||
|
&[I32; 3],
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"invoke_vi",
|
||||||
|
&[I32; 2],
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"invoke_v",
|
||||||
|
&[I32],
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"invoke_iii",
|
||||||
|
&[I32; 3],
|
||||||
|
Some(I32),
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"___resumeException",
|
||||||
|
&[I32],
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"_rust_begin_unwind",
|
||||||
|
&[I32; 4],
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"___cxa_find_matching_catch_2",
|
||||||
|
&[],
|
||||||
|
Some(I32),
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"___gxx_personality_v0",
|
||||||
|
&[I32; 6],
|
||||||
|
Some(I32),
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"_emscripten_memcpy_big",
|
||||||
|
&[I32; 3],
|
||||||
|
Some(I32),
|
||||||
|
)
|
||||||
|
];
|
159
ethcore/src/evm/wasm/mod.rs
Normal file
159
ethcore/src/evm/wasm/mod.rs
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
//! Wasm Interpreter
|
||||||
|
|
||||||
|
mod runtime;
|
||||||
|
mod ptr;
|
||||||
|
mod call_args;
|
||||||
|
mod result;
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
mod env;
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
const DEFAULT_STACK_SPACE: u32 = 5 * 1024 * 1024;
|
||||||
|
|
||||||
|
use parity_wasm::{interpreter, elements};
|
||||||
|
use parity_wasm::interpreter::ModuleInstanceInterface;
|
||||||
|
use wasm_utils;
|
||||||
|
|
||||||
|
use evm::{self, GasLeft, ReturnData};
|
||||||
|
use action_params::ActionParams;
|
||||||
|
use self::runtime::Runtime;
|
||||||
|
|
||||||
|
pub use self::runtime::Error as RuntimeError;
|
||||||
|
|
||||||
|
const DEFAULT_RESULT_BUFFER: usize = 1024;
|
||||||
|
|
||||||
|
/// Wasm interpreter instance
|
||||||
|
pub struct WasmInterpreter {
|
||||||
|
program: interpreter::ProgramInstance,
|
||||||
|
result: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WasmInterpreter {
|
||||||
|
/// New wasm interpreter instance
|
||||||
|
pub fn new() -> Result<WasmInterpreter, RuntimeError> {
|
||||||
|
Ok(WasmInterpreter {
|
||||||
|
program: interpreter::ProgramInstance::new()?,
|
||||||
|
result: Vec::with_capacity(DEFAULT_RESULT_BUFFER),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl evm::Evm for WasmInterpreter {
|
||||||
|
|
||||||
|
fn exec(&mut self, params: ActionParams, ext: &mut evm::Ext) -> evm::Result<GasLeft> {
|
||||||
|
use parity_wasm::elements::Deserialize;
|
||||||
|
|
||||||
|
let code = params.code.expect("exec is only called on contract with code; qed");
|
||||||
|
|
||||||
|
trace!(target: "wasm", "Started wasm interpreter with code.len={:?}", code.len());
|
||||||
|
|
||||||
|
let env_instance = self.program.module("env")
|
||||||
|
// prefer explicit panic here
|
||||||
|
.expect("Wasm program to contain env module");
|
||||||
|
|
||||||
|
let env_memory = env_instance.memory(interpreter::ItemIndex::Internal(0))
|
||||||
|
// prefer explicit panic here
|
||||||
|
.expect("Linear memory to exist in wasm runtime");
|
||||||
|
|
||||||
|
if params.gas > ::std::u64::MAX.into() {
|
||||||
|
return Err(evm::Error::Wasm("Wasm interpreter cannot run contracts with gas >= 2^64".to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut runtime = Runtime::with_params(
|
||||||
|
ext,
|
||||||
|
env_memory,
|
||||||
|
DEFAULT_STACK_SPACE,
|
||||||
|
params.gas.low_u64(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut cursor = ::std::io::Cursor::new(&*code);
|
||||||
|
|
||||||
|
let contract_module = wasm_utils::inject_gas_counter(
|
||||||
|
elements::Module::deserialize(
|
||||||
|
&mut cursor
|
||||||
|
).map_err(|err| {
|
||||||
|
evm::Error::Wasm(format!("Error deserializing contract code ({:?})", err))
|
||||||
|
})?
|
||||||
|
);
|
||||||
|
|
||||||
|
let d_ptr = runtime.write_descriptor(
|
||||||
|
call_args::CallArgs::new(
|
||||||
|
params.address,
|
||||||
|
params.sender,
|
||||||
|
params.origin,
|
||||||
|
params.value.value(),
|
||||||
|
params.data.unwrap_or(Vec::with_capacity(0)),
|
||||||
|
)
|
||||||
|
)?;
|
||||||
|
|
||||||
|
{
|
||||||
|
let execution_params = interpreter::ExecutionParams::with_external(
|
||||||
|
"env".into(),
|
||||||
|
Arc::new(
|
||||||
|
interpreter::env_native_module(env_instance, native_bindings(&mut runtime))
|
||||||
|
.map_err(|err| {
|
||||||
|
// todo: prefer explicit panic here also?
|
||||||
|
evm::Error::Wasm(format!("Error instantiating native bindings: {:?}", err))
|
||||||
|
})?
|
||||||
|
)
|
||||||
|
).add_argument(interpreter::RuntimeValue::I32(d_ptr.as_raw() as i32));
|
||||||
|
|
||||||
|
let module_instance = self.program.add_module("contract", contract_module, Some(&execution_params.externals))
|
||||||
|
.map_err(|err| {
|
||||||
|
trace!(target: "wasm", "Error adding contract module: {:?}", err);
|
||||||
|
evm::Error::from(RuntimeError::Interpreter(err))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
module_instance.execute_export("_call", execution_params)
|
||||||
|
.map_err(|err| {
|
||||||
|
trace!(target: "wasm", "Error executing contract: {:?}", err);
|
||||||
|
evm::Error::from(RuntimeError::Interpreter(err))
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = result::WasmResult::new(d_ptr);
|
||||||
|
if result.peek_empty(&*runtime.memory())? {
|
||||||
|
trace!(target: "wasm", "Contract execution result is empty.");
|
||||||
|
Ok(GasLeft::Known(runtime.gas_left()?.into()))
|
||||||
|
} else {
|
||||||
|
self.result.clear();
|
||||||
|
// todo: use memory views to avoid copy
|
||||||
|
self.result.extend(result.pop(&*runtime.memory())?);
|
||||||
|
let len = self.result.len();
|
||||||
|
Ok(GasLeft::NeedsReturn {
|
||||||
|
gas_left: runtime.gas_left()?.into(),
|
||||||
|
data: ReturnData::new(
|
||||||
|
::std::mem::replace(&mut self.result, Vec::with_capacity(DEFAULT_RESULT_BUFFER)),
|
||||||
|
0,
|
||||||
|
len,
|
||||||
|
),
|
||||||
|
apply_state: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn native_bindings<'a>(runtime: &'a mut Runtime) -> interpreter::UserFunctions<'a> {
|
||||||
|
interpreter::UserFunctions {
|
||||||
|
executor: runtime,
|
||||||
|
functions: ::std::borrow::Cow::from(env::SIGNATURES),
|
||||||
|
}
|
||||||
|
}
|
52
ethcore/src/evm/wasm/ptr.rs
Normal file
52
ethcore/src/evm/wasm/ptr.rs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
//! Wasm bound-checked ptr
|
||||||
|
|
||||||
|
use parity_wasm::interpreter;
|
||||||
|
|
||||||
|
/// Bound-checked wrapper for webassembly memory
|
||||||
|
pub struct WasmPtr(u32);
|
||||||
|
|
||||||
|
/// Error in bound check
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
AccessViolation,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u32> for WasmPtr {
|
||||||
|
fn from(raw: u32) -> Self {
|
||||||
|
WasmPtr(raw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WasmPtr {
|
||||||
|
// todo: use memory view when they are on
|
||||||
|
/// Check memory range and return data with given length starting from the current pointer value
|
||||||
|
pub fn slice(&self, len: u32, mem: &interpreter::MemoryInstance) -> Result<Vec<u8>, Error> {
|
||||||
|
mem.get(self.0, len as usize).map_err(|_| Error::AccessViolation)
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: maybe 2gb limit can be enhanced
|
||||||
|
/// Convert i32 from wasm stack to the wrapped pointer
|
||||||
|
pub fn from_i32(raw_ptr: i32) -> Result<Self, Error> {
|
||||||
|
if raw_ptr < 0 { return Err(Error::AccessViolation); }
|
||||||
|
Ok(WasmPtr(raw_ptr as u32))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return pointer raw value
|
||||||
|
pub fn as_raw(&self) -> u32 { self.0 }
|
||||||
|
}
|
51
ethcore/src/evm/wasm/result.rs
Normal file
51
ethcore/src/evm/wasm/result.rs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
//! Wasm evm results helper
|
||||||
|
|
||||||
|
use byteorder::{LittleEndian, ByteOrder};
|
||||||
|
|
||||||
|
use parity_wasm::interpreter;
|
||||||
|
|
||||||
|
use super::ptr::WasmPtr;
|
||||||
|
use super::runtime::Error as RuntimeError;
|
||||||
|
|
||||||
|
/// Wrapper for wasm contract call result
|
||||||
|
pub struct WasmResult {
|
||||||
|
ptr: WasmPtr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WasmResult {
|
||||||
|
/// New call result from given ptr
|
||||||
|
pub fn new(descriptor_ptr: WasmPtr) -> WasmResult {
|
||||||
|
WasmResult { ptr: descriptor_ptr }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the result contains any data
|
||||||
|
pub fn peek_empty(&self, mem: &interpreter::MemoryInstance) -> Result<bool, RuntimeError> {
|
||||||
|
let result_len = LittleEndian::read_u32(&self.ptr.slice(16, mem)?[12..16]);
|
||||||
|
Ok(result_len == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consume the result ptr and return the actual data from wasm linear memory
|
||||||
|
pub fn pop(self, mem: &interpreter::MemoryInstance) -> Result<Vec<u8>, RuntimeError> {
|
||||||
|
let result_ptr = LittleEndian::read_u32(&self.ptr.slice(16, mem)?[8..12]);
|
||||||
|
let result_len = LittleEndian::read_u32(&self.ptr.slice(16, mem)?[12..16]);
|
||||||
|
trace!(target: "wasm", "contract result: {} bytes at @{}", result_len, result_ptr);
|
||||||
|
|
||||||
|
Ok(mem.get(result_ptr, result_len as usize)?)
|
||||||
|
}
|
||||||
|
}
|
356
ethcore/src/evm/wasm/runtime.rs
Normal file
356
ethcore/src/evm/wasm/runtime.rs
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
//! Wasm evm program runtime intstance
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use byteorder::{LittleEndian, ByteOrder};
|
||||||
|
|
||||||
|
use evm;
|
||||||
|
|
||||||
|
use parity_wasm::interpreter;
|
||||||
|
use util::{Address, H256, U256};
|
||||||
|
|
||||||
|
use super::ptr::{WasmPtr, Error as PtrError};
|
||||||
|
use super::call_args::CallArgs;
|
||||||
|
|
||||||
|
/// Wasm runtime error
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Storage error
|
||||||
|
Storage,
|
||||||
|
/// Allocator error
|
||||||
|
Allocator,
|
||||||
|
/// Invalid gas state during the call
|
||||||
|
InvalidGasState,
|
||||||
|
/// Memory access violation
|
||||||
|
AccessViolation,
|
||||||
|
/// Interpreter runtime error
|
||||||
|
Interpreter(interpreter::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<interpreter::Error> for Error {
|
||||||
|
fn from(err: interpreter::Error) -> Self {
|
||||||
|
Error::Interpreter(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PtrError> for Error {
|
||||||
|
fn from(err: PtrError) -> Self {
|
||||||
|
match err {
|
||||||
|
PtrError::AccessViolation => Error::AccessViolation,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runtime enviroment data for wasm contract execution
|
||||||
|
pub struct Runtime<'a> {
|
||||||
|
gas_counter: u64,
|
||||||
|
gas_limit: u64,
|
||||||
|
dynamic_top: u32,
|
||||||
|
ext: &'a mut evm::Ext,
|
||||||
|
memory: Arc<interpreter::MemoryInstance>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Runtime<'a> {
|
||||||
|
/// New runtime for wasm contract with specified params
|
||||||
|
pub fn with_params<'b>(
|
||||||
|
ext: &'b mut evm::Ext,
|
||||||
|
memory: Arc<interpreter::MemoryInstance>,
|
||||||
|
stack_space: u32,
|
||||||
|
gas_limit: u64,
|
||||||
|
) -> Runtime<'b> {
|
||||||
|
Runtime {
|
||||||
|
gas_counter: 0,
|
||||||
|
gas_limit: gas_limit,
|
||||||
|
dynamic_top: stack_space,
|
||||||
|
memory: memory,
|
||||||
|
ext: ext,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write to the storage from wasm memory
|
||||||
|
pub fn storage_write(&mut self, context: interpreter::CallerContext)
|
||||||
|
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||||
|
{
|
||||||
|
let mut context = context;
|
||||||
|
let val = self.pop_h256(&mut context)?;
|
||||||
|
let key = self.pop_h256(&mut context)?;
|
||||||
|
trace!(target: "wasm", "storage_write: value {} at @{}", &val, &key);
|
||||||
|
|
||||||
|
self.ext.set_storage(key, val)
|
||||||
|
.map_err(|_| interpreter::Error::Trap("Storage update error".to_owned()))?;
|
||||||
|
|
||||||
|
Ok(Some(0i32.into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read from the storage to wasm memory
|
||||||
|
pub fn storage_read(&mut self, context: interpreter::CallerContext)
|
||||||
|
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||||
|
{
|
||||||
|
let mut context = context;
|
||||||
|
let val_ptr = context.value_stack.pop_as::<i32>()?;
|
||||||
|
let key = self.pop_h256(&mut context)?;
|
||||||
|
|
||||||
|
let val = self.ext.storage_at(&key)
|
||||||
|
.map_err(|_| interpreter::Error::Trap("Storage read error".to_owned()))?;
|
||||||
|
|
||||||
|
self.memory.set(val_ptr as u32, &*val)?;
|
||||||
|
|
||||||
|
Ok(Some(0.into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pass suicide to state runtime
|
||||||
|
pub fn suicide(&mut self, context: interpreter::CallerContext)
|
||||||
|
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||||
|
{
|
||||||
|
let mut context = context;
|
||||||
|
let refund_address = self.pop_address(&mut context)?;
|
||||||
|
|
||||||
|
self.ext.suicide(&refund_address)
|
||||||
|
.map_err(|_| interpreter::Error::Trap("Suicide error".to_owned()))?;
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invoke create in the state runtime
|
||||||
|
pub fn create(&mut self, context: interpreter::CallerContext)
|
||||||
|
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// method signature:
|
||||||
|
// fn create(endowment: *const u8, code_ptr: *const u8, code_len: u32, result_ptr: *mut u8) -> i32;
|
||||||
|
//
|
||||||
|
|
||||||
|
trace!(target: "wasm", "runtime: create contract");
|
||||||
|
let mut context = context;
|
||||||
|
let result_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
|
trace!(target: "wasm", " result_ptr: {:?}", result_ptr);
|
||||||
|
let code_len = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
|
trace!(target: "wasm", " code_len: {:?}", code_len);
|
||||||
|
let code_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
|
trace!(target: "wasm", " code_ptr: {:?}", code_ptr);
|
||||||
|
let endowment = self.pop_u256(&mut context)?;
|
||||||
|
trace!(target: "wasm", " val: {:?}", endowment);
|
||||||
|
|
||||||
|
let code = self.memory.get(code_ptr, code_len as usize)?;
|
||||||
|
|
||||||
|
let gas_left = self.gas_left()
|
||||||
|
.map_err(|_| interpreter::Error::Trap("Gas state error".to_owned()))?
|
||||||
|
.into();
|
||||||
|
|
||||||
|
match self.ext.create(&gas_left, &endowment, &code, evm::CreateContractAddress::FromSenderAndCodeHash) {
|
||||||
|
evm::ContractCreateResult::Created(address, gas_left) => {
|
||||||
|
self.memory.set(result_ptr, &*address)?;
|
||||||
|
self.gas_counter = self.gas_limit - gas_left.low_u64();
|
||||||
|
trace!(target: "wasm", "runtime: create contract success (@{:?})", address);
|
||||||
|
Ok(Some(0i32.into()))
|
||||||
|
},
|
||||||
|
evm::ContractCreateResult::Failed => {
|
||||||
|
trace!(target: "wasm", "runtime: create contract fail");
|
||||||
|
Ok(Some((-1i32).into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allocate memory using the wasm stack params
|
||||||
|
pub fn malloc(&mut self, context: interpreter::CallerContext)
|
||||||
|
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||||
|
{
|
||||||
|
let amount = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
|
let previous_top = self.dynamic_top;
|
||||||
|
self.dynamic_top = previous_top + amount;
|
||||||
|
Ok(Some((previous_top as i32).into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allocate memory in wasm memory instance
|
||||||
|
pub fn alloc(&mut self, amount: u32) -> Result<u32, Error> {
|
||||||
|
let previous_top = self.dynamic_top;
|
||||||
|
self.dynamic_top = previous_top + amount;
|
||||||
|
Ok(previous_top.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Report gas cost with the params passed in wasm stack
|
||||||
|
fn gas(&mut self, context: interpreter::CallerContext)
|
||||||
|
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||||
|
{
|
||||||
|
let amount = context.value_stack.pop_as::<i32>()? as u64;
|
||||||
|
if self.charge_gas(amount) {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Err(interpreter::Error::Trap(format!("Gas exceeds limits of {}", self.gas_limit)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn charge_gas(&mut self, amount: u64) -> bool {
|
||||||
|
let prev = self.gas_counter;
|
||||||
|
if prev + amount > self.gas_limit {
|
||||||
|
// exceeds gas
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
self.gas_counter = prev + amount;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn h256_at(&self, ptr: WasmPtr) -> Result<H256, interpreter::Error> {
|
||||||
|
Ok(H256::from_slice(&ptr.slice(32, &*self.memory)
|
||||||
|
.map_err(|_| interpreter::Error::Trap("Memory access violation".to_owned()))?
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_h256(&self, context: &mut interpreter::CallerContext) -> Result<H256, interpreter::Error> {
|
||||||
|
let ptr = WasmPtr::from_i32(context.value_stack.pop_as::<i32>()?)
|
||||||
|
.map_err(|_| interpreter::Error::Trap("Memory access violation".to_owned()))?;
|
||||||
|
self.h256_at(ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_u256(&self, context: &mut interpreter::CallerContext) -> Result<U256, interpreter::Error> {
|
||||||
|
let ptr = WasmPtr::from_i32(context.value_stack.pop_as::<i32>()?)
|
||||||
|
.map_err(|_| interpreter::Error::Trap("Memory access violation".to_owned()))?;
|
||||||
|
self.h256_at(ptr).map(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn address_at(&self, ptr: WasmPtr) -> Result<Address, interpreter::Error> {
|
||||||
|
Ok(Address::from_slice(&ptr.slice(20, &*self.memory)
|
||||||
|
.map_err(|_| interpreter::Error::Trap("Memory access violation".to_owned()))?
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_address(&self, context: &mut interpreter::CallerContext) -> Result<Address, interpreter::Error> {
|
||||||
|
let ptr = WasmPtr::from_i32(context.value_stack.pop_as::<i32>()?)
|
||||||
|
.map_err(|_| interpreter::Error::Trap("Memory access violation".to_owned()))?;
|
||||||
|
self.address_at(ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn user_trap(&mut self, _context: interpreter::CallerContext)
|
||||||
|
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||||
|
{
|
||||||
|
Err(interpreter::Error::Trap("unknown trap".to_owned()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn user_noop(&mut self,
|
||||||
|
_context: interpreter::CallerContext
|
||||||
|
) -> Result<Option<interpreter::RuntimeValue>, interpreter::Error> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write call descriptor to wasm memory
|
||||||
|
pub fn write_descriptor(&mut self, call_args: CallArgs) -> Result<WasmPtr, Error> {
|
||||||
|
let d_ptr = self.alloc(16)?;
|
||||||
|
|
||||||
|
let args_len = call_args.len();
|
||||||
|
let args_ptr = self.alloc(args_len)?;
|
||||||
|
|
||||||
|
// write call descriptor
|
||||||
|
// call descriptor is [args_ptr, args_len, return_ptr, return_len]
|
||||||
|
// all are 4 byte length, last 2 are zeroed
|
||||||
|
let mut d_buf = [0u8; 16];
|
||||||
|
LittleEndian::write_u32(&mut d_buf[0..4], args_ptr);
|
||||||
|
LittleEndian::write_u32(&mut d_buf[4..8], args_len);
|
||||||
|
self.memory.set(d_ptr, &d_buf)?;
|
||||||
|
|
||||||
|
// write call args to memory
|
||||||
|
self.memory.set(args_ptr, &call_args.address)?;
|
||||||
|
self.memory.set(args_ptr+20, &call_args.sender)?;
|
||||||
|
self.memory.set(args_ptr+40, &call_args.origin)?;
|
||||||
|
self.memory.set(args_ptr+60, &call_args.value)?;
|
||||||
|
self.memory.set(args_ptr+92, &call_args.data)?;
|
||||||
|
|
||||||
|
Ok(d_ptr.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn debug_log(&mut self, context: interpreter::CallerContext)
|
||||||
|
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||||
|
{
|
||||||
|
let msg_len = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
|
let msg_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
|
|
||||||
|
let msg = String::from_utf8(self.memory.get(msg_ptr, msg_len as usize)?)
|
||||||
|
.map_err(|_| interpreter::Error::Trap("Debug log utf-8 decoding error".to_owned()))?;
|
||||||
|
|
||||||
|
trace!(target: "wasm", "Contract debug message: {}", msg);
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Query current gas left for execution
|
||||||
|
pub fn gas_left(&self) -> Result<u64, Error> {
|
||||||
|
if self.gas_counter > self.gas_limit { return Err(Error::InvalidGasState); }
|
||||||
|
Ok(self.gas_limit - self.gas_counter)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shared memory reference
|
||||||
|
pub fn memory(&self) -> &interpreter::MemoryInstance {
|
||||||
|
&*self.memory
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mem_copy(&self, context: interpreter::CallerContext)
|
||||||
|
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||||
|
{
|
||||||
|
let len = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
|
let dst = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
|
let src = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
|
|
||||||
|
let mem = self.memory().get(src, len as usize)?;
|
||||||
|
self.memory().set(dst, &mem)?;
|
||||||
|
|
||||||
|
Ok(Some(0i32.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> interpreter::UserFunctionExecutor for Runtime<'a> {
|
||||||
|
fn execute(&mut self, name: &str, context: interpreter::CallerContext)
|
||||||
|
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||||
|
{
|
||||||
|
match name {
|
||||||
|
"_malloc" => {
|
||||||
|
self.malloc(context)
|
||||||
|
},
|
||||||
|
"_free" => {
|
||||||
|
// Since it is arena allocator, free does nothing
|
||||||
|
// todo: update if changed
|
||||||
|
self.user_noop(context)
|
||||||
|
},
|
||||||
|
"_storage_read" => {
|
||||||
|
self.storage_read(context)
|
||||||
|
},
|
||||||
|
"_storage_write" => {
|
||||||
|
self.storage_write(context)
|
||||||
|
},
|
||||||
|
"_suicide" => {
|
||||||
|
self.suicide(context)
|
||||||
|
},
|
||||||
|
"_create" => {
|
||||||
|
self.create(context)
|
||||||
|
},
|
||||||
|
"_debug" => {
|
||||||
|
self.debug_log(context)
|
||||||
|
},
|
||||||
|
"gas" => {
|
||||||
|
self.gas(context)
|
||||||
|
},
|
||||||
|
"_emscripten_memcpy_big" => {
|
||||||
|
self.mem_copy(context)
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
trace!("Unknown env func: '{}'", name);
|
||||||
|
self.user_trap(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
279
ethcore/src/evm/wasm/tests.rs
Normal file
279
ethcore/src/evm/wasm/tests.rs
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use ethcore_logger::init_log;
|
||||||
|
use super::super::tests::{FakeExt, FakeCall, FakeCallType};
|
||||||
|
use super::WasmInterpreter;
|
||||||
|
use evm::{self, Evm, GasLeft};
|
||||||
|
use action_params::{ActionParams, ActionValue};
|
||||||
|
use util::{U256, H256, Address};
|
||||||
|
|
||||||
|
fn load_sample(name: &str) -> Vec<u8> {
|
||||||
|
let mut path = PathBuf::from("./res/wasm-tests/compiled");
|
||||||
|
path.push(name);
|
||||||
|
let mut file = File::open(path).expect(&format!("File {} for test to exist", name));
|
||||||
|
let mut data = vec![];
|
||||||
|
file.read_to_end(&mut data).expect(&format!("Test {} to load ok", name));
|
||||||
|
data
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_finalize(res: Result<GasLeft, evm::Error>) -> Result<U256, evm::Error> {
|
||||||
|
match res {
|
||||||
|
Ok(GasLeft::Known(gas)) => Ok(gas),
|
||||||
|
Ok(GasLeft::NeedsReturn{..}) => unimplemented!(), // since ret is unimplemented.
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wasm_interpreter() -> WasmInterpreter {
|
||||||
|
WasmInterpreter::new().expect("wasm interpreter to create without errors")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Empty contract does almost nothing except producing 1 (one) local node debug log message
|
||||||
|
#[test]
|
||||||
|
fn empty() {
|
||||||
|
init_log();
|
||||||
|
|
||||||
|
let code = load_sample("empty.wasm");
|
||||||
|
let address: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
|
||||||
|
|
||||||
|
let mut params = ActionParams::default();
|
||||||
|
params.address = address.clone();
|
||||||
|
params.gas = U256::from(100_000);
|
||||||
|
params.code = Some(Arc::new(code));
|
||||||
|
let mut ext = FakeExt::new();
|
||||||
|
|
||||||
|
let gas_left = {
|
||||||
|
let mut interpreter = wasm_interpreter();
|
||||||
|
test_finalize(interpreter.exec(params, &mut ext)).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(gas_left, U256::from(99_996));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This test checks if the contract deserializes payload header properly.
|
||||||
|
// Contract is provided with receiver(address), sender, origin and transaction value
|
||||||
|
// logger.wasm writes all these provided fixed header fields to some arbitrary storage keys.
|
||||||
|
#[test]
|
||||||
|
fn logger() {
|
||||||
|
init_log();
|
||||||
|
|
||||||
|
let code = load_sample("logger.wasm");
|
||||||
|
let address: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
|
||||||
|
let sender: Address = "0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d".parse().unwrap();
|
||||||
|
let origin: Address = "0102030405060708090a0b0c0d0e0f1011121314".parse().unwrap();
|
||||||
|
|
||||||
|
let mut params = ActionParams::default();
|
||||||
|
params.address = address.clone();
|
||||||
|
params.sender = sender.clone();
|
||||||
|
params.origin = origin.clone();
|
||||||
|
params.gas = U256::from(100_000);
|
||||||
|
params.value = ActionValue::transfer(1_000_000_000);
|
||||||
|
params.code = Some(Arc::new(code));
|
||||||
|
let mut ext = FakeExt::new();
|
||||||
|
|
||||||
|
let gas_left = {
|
||||||
|
let mut interpreter = wasm_interpreter();
|
||||||
|
test_finalize(interpreter.exec(params, &mut ext)).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("ext.store: {:?}", ext.store);
|
||||||
|
assert_eq!(gas_left, U256::from(99581));
|
||||||
|
let address_val: H256 = address.into();
|
||||||
|
assert_eq!(
|
||||||
|
ext.store.get(&"0100000000000000000000000000000000000000000000000000000000000000".parse().unwrap()).expect("storage key to exist"),
|
||||||
|
&address_val,
|
||||||
|
"Logger sets 0x01 key to the provided address"
|
||||||
|
);
|
||||||
|
let sender_val: H256 = sender.into();
|
||||||
|
assert_eq!(
|
||||||
|
ext.store.get(&"0200000000000000000000000000000000000000000000000000000000000000".parse().unwrap()).expect("storage key to exist"),
|
||||||
|
&sender_val,
|
||||||
|
"Logger sets 0x02 key to the provided sender"
|
||||||
|
);
|
||||||
|
let origin_val: H256 = origin.into();
|
||||||
|
assert_eq!(
|
||||||
|
ext.store.get(&"0300000000000000000000000000000000000000000000000000000000000000".parse().unwrap()).expect("storage key to exist"),
|
||||||
|
&origin_val,
|
||||||
|
"Logger sets 0x03 key to the provided origin"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
U256::from(ext.store.get(&"0400000000000000000000000000000000000000000000000000000000000000".parse().unwrap()).expect("storage key to exist")),
|
||||||
|
U256::from(1_000_000_000),
|
||||||
|
"Logger sets 0x04 key to the trasferred value"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This test checks if the contract can allocate memory and pass pointer to the result stream properly.
|
||||||
|
// 1. Contract is being provided with the call descriptor ptr
|
||||||
|
// 2. Descriptor ptr is 16 byte length
|
||||||
|
// 3. The last 8 bytes of call descriptor is the space for the contract to fill [result_ptr[4], result_len[4]]
|
||||||
|
// if it has any result.
|
||||||
|
#[test]
|
||||||
|
fn identity() {
|
||||||
|
init_log();
|
||||||
|
|
||||||
|
let code = load_sample("identity.wasm");
|
||||||
|
let sender: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap();
|
||||||
|
|
||||||
|
let mut params = ActionParams::default();
|
||||||
|
params.sender = sender.clone();
|
||||||
|
params.gas = U256::from(100_000);
|
||||||
|
params.code = Some(Arc::new(code));
|
||||||
|
let mut ext = FakeExt::new();
|
||||||
|
|
||||||
|
let (gas_left, result) = {
|
||||||
|
let mut interpreter = wasm_interpreter();
|
||||||
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
||||||
|
match result {
|
||||||
|
GasLeft::Known(_) => { panic!("Identity contract should return payload"); },
|
||||||
|
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(gas_left, U256::from(99_689));
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Address::from_slice(&result),
|
||||||
|
sender,
|
||||||
|
"Idenity test contract does not return the sender passed"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dispersion test sends byte array and expect the contract to 'disperse' the original elements with
|
||||||
|
// their modulo 19 dopant.
|
||||||
|
// The result is always twice as long as the input.
|
||||||
|
// This also tests byte-perfect memory allocation and in/out ptr lifecycle.
|
||||||
|
#[test]
|
||||||
|
fn dispersion() {
|
||||||
|
init_log();
|
||||||
|
|
||||||
|
let code = load_sample("dispersion.wasm");
|
||||||
|
|
||||||
|
let mut params = ActionParams::default();
|
||||||
|
params.gas = U256::from(100_000);
|
||||||
|
params.code = Some(Arc::new(code));
|
||||||
|
params.data = Some(vec![
|
||||||
|
0u8, 125, 197, 255, 19
|
||||||
|
]);
|
||||||
|
let mut ext = FakeExt::new();
|
||||||
|
|
||||||
|
let (gas_left, result) = {
|
||||||
|
let mut interpreter = wasm_interpreter();
|
||||||
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
||||||
|
match result {
|
||||||
|
GasLeft::Known(_) => { panic!("Dispersion routine should return payload"); },
|
||||||
|
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(gas_left, U256::from(99_402));
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
result,
|
||||||
|
vec![0u8, 0, 125, 11, 197, 7, 255, 8, 19, 0]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn suicide_not() {
|
||||||
|
init_log();
|
||||||
|
|
||||||
|
let code = load_sample("suicidal.wasm");
|
||||||
|
|
||||||
|
let mut params = ActionParams::default();
|
||||||
|
params.gas = U256::from(100_000);
|
||||||
|
params.code = Some(Arc::new(code));
|
||||||
|
params.data = Some(vec![
|
||||||
|
0u8
|
||||||
|
]);
|
||||||
|
let mut ext = FakeExt::new();
|
||||||
|
|
||||||
|
let (gas_left, result) = {
|
||||||
|
let mut interpreter = wasm_interpreter();
|
||||||
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
||||||
|
match result {
|
||||||
|
GasLeft::Known(_) => { panic!("Suicidal contract should return payload when had not actualy killed himself"); },
|
||||||
|
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(gas_left, U256::from(99_703));
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
result,
|
||||||
|
vec![0u8]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn suicide() {
|
||||||
|
init_log();
|
||||||
|
|
||||||
|
let code = load_sample("suicidal.wasm");
|
||||||
|
|
||||||
|
let refund: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap();
|
||||||
|
let mut params = ActionParams::default();
|
||||||
|
params.gas = U256::from(100_000);
|
||||||
|
params.code = Some(Arc::new(code));
|
||||||
|
|
||||||
|
let mut args = vec![127u8];
|
||||||
|
args.extend(refund.to_vec());
|
||||||
|
params.data = Some(args);
|
||||||
|
|
||||||
|
let mut ext = FakeExt::new();
|
||||||
|
|
||||||
|
let gas_left = {
|
||||||
|
let mut interpreter = wasm_interpreter();
|
||||||
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
||||||
|
match result {
|
||||||
|
GasLeft::Known(gas) => gas,
|
||||||
|
GasLeft::NeedsReturn { .. } => {
|
||||||
|
panic!("Suicidal contract should not return anything when had killed itself");
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(gas_left, U256::from(99_747));
|
||||||
|
assert!(ext.suicides.contains(&refund));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create() {
|
||||||
|
init_log();
|
||||||
|
|
||||||
|
let mut params = ActionParams::default();
|
||||||
|
params.gas = U256::from(100_000);
|
||||||
|
params.code = Some(Arc::new(load_sample("creator.wasm")));
|
||||||
|
params.data = Some(vec![0u8, 2, 4, 8, 16, 32, 64, 128]);
|
||||||
|
params.value = ActionValue::transfer(1_000_000_000);
|
||||||
|
|
||||||
|
let mut ext = FakeExt::new();
|
||||||
|
|
||||||
|
let gas_left = {
|
||||||
|
let mut interpreter = wasm_interpreter();
|
||||||
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
||||||
|
match result {
|
||||||
|
GasLeft::Known(gas) => gas,
|
||||||
|
GasLeft::NeedsReturn { .. } => {
|
||||||
|
panic!("Create contract should not return anthing because ext always fails on creation");
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
trace!(target: "wasm", "fake_calls: {:?}", &ext.calls);
|
||||||
|
assert!(ext.calls.contains(
|
||||||
|
&FakeCall {
|
||||||
|
call_type: FakeCallType::Create,
|
||||||
|
gas: U256::from(99_778),
|
||||||
|
sender_address: None,
|
||||||
|
receive_address: None,
|
||||||
|
value: Some(1_000_000_000.into()),
|
||||||
|
data: vec![0u8, 2, 4, 8, 16, 32, 64, 128],
|
||||||
|
code_address: None,
|
||||||
|
}
|
||||||
|
));
|
||||||
|
assert_eq!(gas_left, U256::from(99_768));
|
||||||
|
}
|
@ -22,7 +22,7 @@ use engines::Engine;
|
|||||||
use types::executed::CallType;
|
use types::executed::CallType;
|
||||||
use env_info::EnvInfo;
|
use env_info::EnvInfo;
|
||||||
use error::ExecutionError;
|
use error::ExecutionError;
|
||||||
use evm::{self, Ext, Finalize, CreateContractAddress, FinalizationResult, ReturnData, CleanDustMode};
|
use evm::{self, wasm, Factory, Ext, Finalize, CreateContractAddress, FinalizationResult, ReturnData, CleanDustMode};
|
||||||
use externalities::*;
|
use externalities::*;
|
||||||
use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer};
|
use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer};
|
||||||
use transaction::{Action, SignedTransaction};
|
use transaction::{Action, SignedTransaction};
|
||||||
@ -34,6 +34,8 @@ pub use types::executed::{Executed, ExecutionResult};
|
|||||||
/// Maybe something like here: `https://github.com/ethereum/libethereum/blob/4db169b8504f2b87f7d5a481819cfb959fc65f6c/libethereum/ExtVM.cpp`
|
/// Maybe something like here: `https://github.com/ethereum/libethereum/blob/4db169b8504f2b87f7d5a481819cfb959fc65f6c/libethereum/ExtVM.cpp`
|
||||||
const STACK_SIZE_PER_DEPTH: usize = 24*1024;
|
const STACK_SIZE_PER_DEPTH: usize = 24*1024;
|
||||||
|
|
||||||
|
const WASM_MAGIC_NUMBER: &'static [u8; 4] = b"\0asm";
|
||||||
|
|
||||||
/// Returns new address created from address, nonce, and code hash
|
/// Returns new address created from address, nonce, and code hash
|
||||||
pub fn contract_address(address_scheme: CreateContractAddress, sender: &Address, nonce: &U256, code: &[u8]) -> (Address, Option<H256>) {
|
pub fn contract_address(address_scheme: CreateContractAddress, sender: &Address, nonce: &U256, code: &[u8]) -> (Address, Option<H256>) {
|
||||||
use rlp::RlpStream;
|
use rlp::RlpStream;
|
||||||
@ -72,6 +74,20 @@ pub struct TransactOptions {
|
|||||||
pub check_nonce: bool,
|
pub check_nonce: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn executor<E>(engine: &E, vm_factory: &Factory, params: &ActionParams)
|
||||||
|
-> Box<evm::Evm> where E: Engine + ?Sized
|
||||||
|
{
|
||||||
|
if engine.supports_wasm() && params.code.as_ref().map_or(false, |code| code.len() > 4 && &code[0..4] == WASM_MAGIC_NUMBER) {
|
||||||
|
Box::new(
|
||||||
|
wasm::WasmInterpreter::new()
|
||||||
|
// prefer to fail fast
|
||||||
|
.expect("Failed to create wasm runtime")
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
vm_factory.create(params.gas)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Transaction executor.
|
/// Transaction executor.
|
||||||
pub struct Executive<'a, B: 'a + StateBackend, E: 'a + Engine + ?Sized> {
|
pub struct Executive<'a, B: 'a + StateBackend, E: 'a + Engine + ?Sized> {
|
||||||
state: &'a mut State<B>,
|
state: &'a mut State<B>,
|
||||||
@ -263,18 +279,19 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
|||||||
let vm_factory = self.state.vm_factory();
|
let vm_factory = self.state.vm_factory();
|
||||||
let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call);
|
let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call);
|
||||||
trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call);
|
trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call);
|
||||||
return vm_factory.create(params.gas).exec(params, &mut ext).finalize(ext);
|
return executor(self.engine, &vm_factory, ¶ms).exec(params, &mut ext).finalize(ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start in new thread to reset stack
|
// Start in new thread to reset stack
|
||||||
// TODO [todr] No thread builder yet, so we need to reset once for a while
|
// TODO [todr] No thread builder yet, so we need to reset once for a while
|
||||||
// https://github.com/aturon/crossbeam/issues/16
|
// https://github.com/aturon/crossbeam/issues/16
|
||||||
crossbeam::scope(|scope| {
|
crossbeam::scope(|scope| {
|
||||||
|
let engine = self.engine;
|
||||||
let vm_factory = self.state.vm_factory();
|
let vm_factory = self.state.vm_factory();
|
||||||
let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call);
|
let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call);
|
||||||
|
|
||||||
scope.spawn(move || {
|
scope.spawn(move || {
|
||||||
vm_factory.create(params.gas).exec(params, &mut ext).finalize(ext)
|
executor(engine, &vm_factory, ¶ms).exec(params, &mut ext).finalize(ext)
|
||||||
})
|
})
|
||||||
}).join()
|
}).join()
|
||||||
}
|
}
|
||||||
@ -376,7 +393,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
|||||||
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()), &mut subtracer, &mut subvmtracer)
|
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()), &mut subtracer, &mut subvmtracer)
|
||||||
};
|
};
|
||||||
|
|
||||||
vm_tracer.done_subtrace(subvmtracer, res.is_ok());
|
vm_tracer.done_subtrace(subvmtracer);
|
||||||
|
|
||||||
trace!(target: "executive", "res={:?}", res);
|
trace!(target: "executive", "res={:?}", res);
|
||||||
|
|
||||||
@ -457,7 +474,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
|||||||
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(trace_output.as_mut()), &mut subtracer, &mut subvmtracer)
|
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(trace_output.as_mut()), &mut subtracer, &mut subvmtracer)
|
||||||
};
|
};
|
||||||
|
|
||||||
vm_tracer.done_subtrace(subvmtracer, res.is_ok());
|
vm_tracer.done_subtrace(subvmtracer);
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Ok(ref res) => tracer.trace_create(
|
Ok(ref res) => tracer.trace_create(
|
||||||
@ -562,6 +579,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
|||||||
| Err(evm::Error::BadInstruction {.. })
|
| Err(evm::Error::BadInstruction {.. })
|
||||||
| Err(evm::Error::StackUnderflow {..})
|
| Err(evm::Error::StackUnderflow {..})
|
||||||
| Err(evm::Error::BuiltIn {..})
|
| Err(evm::Error::BuiltIn {..})
|
||||||
|
| Err(evm::Error::Wasm {..})
|
||||||
| Err(evm::Error::OutOfStack {..})
|
| Err(evm::Error::OutOfStack {..})
|
||||||
| Err(evm::Error::MutableCallInStaticContext)
|
| Err(evm::Error::MutableCallInStaticContext)
|
||||||
| Ok(FinalizationResult { apply_state: false, .. }) => {
|
| Ok(FinalizationResult { apply_state: false, .. }) => {
|
||||||
|
@ -379,7 +379,11 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
|
|||||||
self.substate.sstore_clears_count = self.substate.sstore_clears_count + U256::one();
|
self.substate.sstore_clears_count = self.substate.sstore_clears_count + U256::one();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trace_prepare_execute(&mut self, pc: usize, instruction: u8, gas_cost: &U256) -> bool {
|
fn trace_next_instruction(&mut self, pc: usize, instruction: u8) -> bool {
|
||||||
|
self.vm_tracer.trace_next_instruction(pc, instruction)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trace_prepare_execute(&mut self, pc: usize, instruction: u8, gas_cost: U256) {
|
||||||
self.vm_tracer.trace_prepare_execute(pc, instruction, gas_cost)
|
self.vm_tracer.trace_prepare_execute(pc, instruction, gas_cost)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,6 +105,8 @@ extern crate semver;
|
|||||||
extern crate stats;
|
extern crate stats;
|
||||||
extern crate time;
|
extern crate time;
|
||||||
extern crate transient_hashmap;
|
extern crate transient_hashmap;
|
||||||
|
extern crate parity_wasm;
|
||||||
|
extern crate wasm_utils;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
@ -88,6 +88,8 @@ pub struct MinerOptions {
|
|||||||
pub reseal_on_external_tx: bool,
|
pub reseal_on_external_tx: bool,
|
||||||
/// Reseal on receipt of new local transactions.
|
/// Reseal on receipt of new local transactions.
|
||||||
pub reseal_on_own_tx: bool,
|
pub reseal_on_own_tx: bool,
|
||||||
|
/// Reseal when new uncle block has been imported.
|
||||||
|
pub reseal_on_uncle: bool,
|
||||||
/// Minimum period between transaction-inspired reseals.
|
/// Minimum period between transaction-inspired reseals.
|
||||||
pub reseal_min_period: Duration,
|
pub reseal_min_period: Duration,
|
||||||
/// Maximum period between blocks (enables force sealing after that).
|
/// Maximum period between blocks (enables force sealing after that).
|
||||||
@ -119,6 +121,7 @@ impl Default for MinerOptions {
|
|||||||
force_sealing: false,
|
force_sealing: false,
|
||||||
reseal_on_external_tx: false,
|
reseal_on_external_tx: false,
|
||||||
reseal_on_own_tx: true,
|
reseal_on_own_tx: true,
|
||||||
|
reseal_on_uncle: false,
|
||||||
tx_gas_limit: !U256::zero(),
|
tx_gas_limit: !U256::zero(),
|
||||||
tx_queue_size: 1024,
|
tx_queue_size: 1024,
|
||||||
tx_queue_gas_limit: GasLimit::Auto,
|
tx_queue_gas_limit: GasLimit::Auto,
|
||||||
@ -347,7 +350,7 @@ impl Miner {
|
|||||||
Some(old_block) => {
|
Some(old_block) => {
|
||||||
trace!(target: "miner", "prepare_block: Already have previous work; updating and returning");
|
trace!(target: "miner", "prepare_block: Already have previous work; updating and returning");
|
||||||
// add transactions to old_block
|
// add transactions to old_block
|
||||||
old_block.reopen(&*self.engine)
|
chain.reopen_block(old_block)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// block not found - create it.
|
// block not found - create it.
|
||||||
@ -366,7 +369,6 @@ impl Miner {
|
|||||||
let mut transactions_to_penalize = HashSet::new();
|
let mut transactions_to_penalize = HashSet::new();
|
||||||
let block_number = open_block.block().fields().header.number();
|
let block_number = open_block.block().fields().header.number();
|
||||||
|
|
||||||
// TODO Push new uncles too.
|
|
||||||
let mut tx_count: usize = 0;
|
let mut tx_count: usize = 0;
|
||||||
let tx_total = transactions.len();
|
let tx_total = transactions.len();
|
||||||
for tx in transactions {
|
for tx in transactions {
|
||||||
@ -1153,11 +1155,10 @@ impl MinerService for Miner {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chain_new_blocks(&self, chain: &MiningBlockChainClient, _imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256]) {
|
fn chain_new_blocks(&self, chain: &MiningBlockChainClient, imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256]) {
|
||||||
trace!(target: "miner", "chain_new_blocks");
|
trace!(target: "miner", "chain_new_blocks");
|
||||||
|
|
||||||
// 1. We ignore blocks that were `imported` (because it means that they are not in canon-chain, and transactions
|
// 1. We ignore blocks that were `imported` unless resealing on new uncles is enabled.
|
||||||
// should be still available in the queue.
|
|
||||||
// 2. We ignore blocks that are `invalid` because it doesn't have any meaning in terms of the transactions that
|
// 2. We ignore blocks that are `invalid` because it doesn't have any meaning in terms of the transactions that
|
||||||
// are in those blocks
|
// are in those blocks
|
||||||
|
|
||||||
@ -1192,7 +1193,7 @@ impl MinerService for Miner {
|
|||||||
transaction_queue.remove_old(&fetch_account, time);
|
transaction_queue.remove_old(&fetch_account, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
if enacted.len() > 0 {
|
if enacted.len() > 0 || (imported.len() > 0 && self.options.reseal_on_uncle) {
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// | NOTE Code below requires transaction_queue and sealing_work locks. |
|
// | NOTE Code below requires transaction_queue and sealing_work locks. |
|
||||||
// | Make sure to release the locks before calling that method. |
|
// | Make sure to release the locks before calling that method. |
|
||||||
@ -1312,6 +1313,7 @@ mod tests {
|
|||||||
force_sealing: false,
|
force_sealing: false,
|
||||||
reseal_on_external_tx: false,
|
reseal_on_external_tx: false,
|
||||||
reseal_on_own_tx: true,
|
reseal_on_own_tx: true,
|
||||||
|
reseal_on_uncle: false,
|
||||||
reseal_min_period: Duration::from_secs(5),
|
reseal_min_period: Duration::from_secs(5),
|
||||||
reseal_max_period: Duration::from_secs(120),
|
reseal_max_period: Duration::from_secs(120),
|
||||||
tx_gas_limit: !U256::zero(),
|
tx_gas_limit: !U256::zero(),
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
//! use ethcore::miner::{Miner, MinerService};
|
//! use ethcore::miner::{Miner, MinerService};
|
||||||
//!
|
//!
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
//! let miner: Miner = Miner::with_spec(ðereum::new_foundation());
|
//! let miner: Miner = Miner::with_spec(ðereum::new_foundation(&env::temp_dir()));
|
||||||
//! // get status
|
//! // get status
|
||||||
//! assert_eq!(miner.status().transactions_in_pending_queue, 0);
|
//! assert_eq!(miner.status().transactions_in_pending_queue, 0);
|
||||||
//!
|
//!
|
||||||
|
@ -59,7 +59,7 @@ lazy_static! {
|
|||||||
/// `native_contracts::test_contracts::ValidatorSet` provides a native wrapper for the ABi.
|
/// `native_contracts::test_contracts::ValidatorSet` provides a native wrapper for the ABi.
|
||||||
fn spec_fixed_to_contract() -> Spec {
|
fn spec_fixed_to_contract() -> Spec {
|
||||||
let data = include_bytes!("test_validator_contract.json");
|
let data = include_bytes!("test_validator_contract.json");
|
||||||
Spec::load(&data[..]).unwrap()
|
Spec::load(&::std::env::temp_dir(), &data[..]).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
// creates an account provider, filling it with accounts from all the given
|
// creates an account provider, filling it with accounts from all the given
|
||||||
|
@ -83,6 +83,8 @@ pub struct CommonParams {
|
|||||||
pub nonce_cap_increment: u64,
|
pub nonce_cap_increment: u64,
|
||||||
/// Enable dust cleanup for contracts.
|
/// Enable dust cleanup for contracts.
|
||||||
pub remove_dust_contracts: bool,
|
pub remove_dust_contracts: bool,
|
||||||
|
/// Wasm support
|
||||||
|
pub wasm: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ethjson::spec::Params> for CommonParams {
|
impl From<ethjson::spec::Params> for CommonParams {
|
||||||
@ -110,6 +112,7 @@ impl From<ethjson::spec::Params> for CommonParams {
|
|||||||
dust_protection_transition: p.dust_protection_transition.map_or(BlockNumber::max_value(), Into::into),
|
dust_protection_transition: p.dust_protection_transition.map_or(BlockNumber::max_value(), Into::into),
|
||||||
nonce_cap_increment: p.nonce_cap_increment.map_or(64, Into::into),
|
nonce_cap_increment: p.nonce_cap_increment.map_or(64, Into::into),
|
||||||
remove_dust_contracts: p.remove_dust_contracts.unwrap_or(false),
|
remove_dust_contracts: p.remove_dust_contracts.unwrap_or(false),
|
||||||
|
wasm: p.wasm.unwrap_or(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,7 +161,7 @@ pub struct Spec {
|
|||||||
genesis_state: PodState,
|
genesis_state: PodState,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_from(s: ethjson::spec::Spec) -> Result<Spec, Error> {
|
fn load_from<T: AsRef<Path>>(cache_dir: T, s: ethjson::spec::Spec) -> Result<Spec, Error> {
|
||||||
let builtins = s.accounts.builtins().into_iter().map(|p| (p.0.into(), From::from(p.1))).collect();
|
let builtins = s.accounts.builtins().into_iter().map(|p| (p.0.into(), From::from(p.1))).collect();
|
||||||
let g = Genesis::from(s.genesis);
|
let g = Genesis::from(s.genesis);
|
||||||
let GenericSeal(seal_rlp) = g.seal.into();
|
let GenericSeal(seal_rlp) = g.seal.into();
|
||||||
@ -166,7 +169,7 @@ fn load_from(s: ethjson::spec::Spec) -> Result<Spec, Error> {
|
|||||||
|
|
||||||
let mut s = Spec {
|
let mut s = Spec {
|
||||||
name: s.name.clone().into(),
|
name: s.name.clone().into(),
|
||||||
engine: Spec::engine(s.engine, params, builtins),
|
engine: Spec::engine(cache_dir, s.engine, params, builtins),
|
||||||
data_dir: s.data_dir.unwrap_or(s.name).into(),
|
data_dir: s.data_dir.unwrap_or(s.name).into(),
|
||||||
nodes: s.nodes.unwrap_or_else(Vec::new),
|
nodes: s.nodes.unwrap_or_else(Vec::new),
|
||||||
parent_hash: g.parent_hash,
|
parent_hash: g.parent_hash,
|
||||||
@ -195,18 +198,26 @@ fn load_from(s: ethjson::spec::Spec) -> Result<Spec, Error> {
|
|||||||
|
|
||||||
macro_rules! load_bundled {
|
macro_rules! load_bundled {
|
||||||
($e:expr) => {
|
($e:expr) => {
|
||||||
Spec::load(include_bytes!(concat!("../../res/", $e, ".json")) as &[u8]).expect(concat!("Chain spec ", $e, " is invalid."))
|
Spec::load(
|
||||||
|
&::std::env::temp_dir(),
|
||||||
|
include_bytes!(concat!("../../res/", $e, ".json")) as &[u8]
|
||||||
|
).expect(concat!("Chain spec ", $e, " is invalid."))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Spec {
|
impl Spec {
|
||||||
/// Convert engine spec into a arc'd Engine of the right underlying type.
|
/// Convert engine spec into a arc'd Engine of the right underlying type.
|
||||||
/// TODO avoid this hard-coded nastiness - use dynamic-linked plugin framework instead.
|
/// TODO avoid this hard-coded nastiness - use dynamic-linked plugin framework instead.
|
||||||
fn engine(engine_spec: ethjson::spec::Engine, params: CommonParams, builtins: BTreeMap<Address, Builtin>) -> Arc<Engine> {
|
fn engine<T: AsRef<Path>>(
|
||||||
|
cache_dir: T,
|
||||||
|
engine_spec: ethjson::spec::Engine,
|
||||||
|
params: CommonParams,
|
||||||
|
builtins: BTreeMap<Address, Builtin>,
|
||||||
|
) -> Arc<Engine> {
|
||||||
match engine_spec {
|
match engine_spec {
|
||||||
ethjson::spec::Engine::Null => Arc::new(NullEngine::new(params, builtins)),
|
ethjson::spec::Engine::Null => Arc::new(NullEngine::new(params, builtins)),
|
||||||
ethjson::spec::Engine::InstantSeal(instant) => Arc::new(InstantSeal::new(params, instant.params.registrar.map_or_else(Address::new, Into::into), builtins)),
|
ethjson::spec::Engine::InstantSeal(instant) => Arc::new(InstantSeal::new(params, instant.params.registrar.map_or_else(Address::new, Into::into), builtins)),
|
||||||
ethjson::spec::Engine::Ethash(ethash) => Arc::new(ethereum::Ethash::new(params, From::from(ethash.params), builtins)),
|
ethjson::spec::Engine::Ethash(ethash) => Arc::new(ethereum::Ethash::new(cache_dir, params, From::from(ethash.params), builtins)),
|
||||||
ethjson::spec::Engine::BasicAuthority(basic_authority) => Arc::new(BasicAuthority::new(params, From::from(basic_authority.params), builtins)),
|
ethjson::spec::Engine::BasicAuthority(basic_authority) => Arc::new(BasicAuthority::new(params, From::from(basic_authority.params), builtins)),
|
||||||
ethjson::spec::Engine::AuthorityRound(authority_round) => AuthorityRound::new(params, From::from(authority_round.params), builtins).expect("Failed to start AuthorityRound consensus engine."),
|
ethjson::spec::Engine::AuthorityRound(authority_round) => AuthorityRound::new(params, From::from(authority_round.params), builtins).expect("Failed to start AuthorityRound consensus engine."),
|
||||||
ethjson::spec::Engine::Tendermint(tendermint) => Tendermint::new(params, From::from(tendermint.params), builtins).expect("Failed to start the Tendermint consensus engine."),
|
ethjson::spec::Engine::Tendermint(tendermint) => Tendermint::new(params, From::from(tendermint.params), builtins).expect("Failed to start the Tendermint consensus engine."),
|
||||||
@ -397,13 +408,13 @@ impl Spec {
|
|||||||
|
|
||||||
/// Loads spec from json file. Provide factories for executing contracts and ensuring
|
/// Loads spec from json file. Provide factories for executing contracts and ensuring
|
||||||
/// storage goes to the right place.
|
/// storage goes to the right place.
|
||||||
pub fn load<R>(reader: R) -> Result<Self, String> where R: Read {
|
pub fn load<T: AsRef<Path>, R>(cache_dir: T, reader: R) -> Result<Self, String> where R: Read {
|
||||||
fn fmt<F: ::std::fmt::Display>(f: F) -> String {
|
fn fmt<F: ::std::fmt::Display>(f: F) -> String {
|
||||||
format!("Spec json is invalid: {}", f)
|
format!("Spec json is invalid: {}", f)
|
||||||
}
|
}
|
||||||
|
|
||||||
ethjson::spec::Spec::load(reader).map_err(fmt)
|
ethjson::spec::Spec::load(reader).map_err(fmt)
|
||||||
.and_then(|x| load_from(x).map_err(fmt))
|
.and_then(|x| load_from(cache_dir, x).map_err(fmt))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new Spec which conforms to the Frontier-era Morden chain except that it's a NullEngine consensus.
|
/// Create a new Spec which conforms to the Frontier-era Morden chain except that it's a NullEngine consensus.
|
||||||
@ -453,7 +464,20 @@ mod tests {
|
|||||||
// https://github.com/paritytech/parity/issues/1840
|
// https://github.com/paritytech/parity/issues/1840
|
||||||
#[test]
|
#[test]
|
||||||
fn test_load_empty() {
|
fn test_load_empty() {
|
||||||
assert!(Spec::load(&[] as &[u8]).is_err());
|
assert!(Spec::load(::std::env::temp_dir(), &[] as &[u8]).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn all_spec_files_valid() {
|
||||||
|
Spec::new_test();
|
||||||
|
Spec::new_null();
|
||||||
|
Spec::new_test_constructor();
|
||||||
|
Spec::new_instant();
|
||||||
|
Spec::new_test_round();
|
||||||
|
Spec::new_test_tendermint();
|
||||||
|
Spec::new_validator_safe_contract();
|
||||||
|
Spec::new_validator_contract();
|
||||||
|
Spec::new_validator_multi();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -52,7 +52,7 @@ fn imports_from_empty() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn should_return_registrar() {
|
fn should_return_registrar() {
|
||||||
let dir = RandomTempPath::new();
|
let dir = RandomTempPath::new();
|
||||||
let spec = ethereum::new_morden();
|
let spec = ethereum::new_morden(&dir);
|
||||||
let db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS);
|
let db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS);
|
||||||
let client_db = Arc::new(Database::open(&db_config, dir.as_path().to_str().unwrap()).unwrap());
|
let client_db = Arc::new(Database::open(&db_config, dir.as_path().to_str().unwrap()).unwrap());
|
||||||
|
|
||||||
|
@ -192,14 +192,15 @@ impl ExecutiveVMTracer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl VMTracer for ExecutiveVMTracer {
|
impl VMTracer for ExecutiveVMTracer {
|
||||||
fn trace_prepare_execute(&mut self, pc: usize, instruction: u8, gas_cost: &U256) -> bool {
|
fn trace_next_instruction(&mut self, _pc: usize, _instruction: u8) -> bool { true }
|
||||||
|
|
||||||
|
fn trace_prepare_execute(&mut self, pc: usize, instruction: u8, gas_cost: U256) {
|
||||||
self.data.operations.push(VMOperation {
|
self.data.operations.push(VMOperation {
|
||||||
pc: pc,
|
pc: pc,
|
||||||
instruction: instruction,
|
instruction: instruction,
|
||||||
gas_cost: gas_cost.clone(),
|
gas_cost: gas_cost,
|
||||||
executed: None,
|
executed: None,
|
||||||
});
|
});
|
||||||
true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trace_executed(&mut self, gas_used: U256, stack_push: &[U256], mem_diff: Option<(usize, &[u8])>, store_diff: Option<(U256, U256)>) {
|
fn trace_executed(&mut self, gas_used: U256, stack_push: &[U256], mem_diff: Option<(usize, &[u8])>, store_diff: Option<(U256, U256)>) {
|
||||||
@ -221,7 +222,7 @@ impl VMTracer for ExecutiveVMTracer {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn done_subtrace(&mut self, sub: Self, _is_successful: bool) {
|
fn done_subtrace(&mut self, sub: Self) {
|
||||||
self.data.subs.push(sub.data);
|
self.data.subs.push(sub.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,18 +87,23 @@ pub trait Tracer: Send {
|
|||||||
|
|
||||||
/// Used by executive to build VM traces.
|
/// Used by executive to build VM traces.
|
||||||
pub trait VMTracer: Send {
|
pub trait VMTracer: Send {
|
||||||
/// Trace the preparation to execute a single instruction.
|
|
||||||
/// @returns true if `trace_executed` should be called.
|
|
||||||
fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _gas_cost: &U256) -> bool { false }
|
|
||||||
|
|
||||||
/// Trace the finalised execution of a single instruction.
|
/// Trace the progression of interpreter to next instruction.
|
||||||
|
/// If tracer returns `false` it won't be called again.
|
||||||
|
/// @returns true if `trace_prepare_execute` and `trace_executed` should be called.
|
||||||
|
fn trace_next_instruction(&mut self, _pc: usize, _instruction: u8) -> bool { false }
|
||||||
|
|
||||||
|
/// Trace the preparation to execute a single valid instruction.
|
||||||
|
fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _gas_cost: U256) {}
|
||||||
|
|
||||||
|
/// Trace the finalised execution of a single valid instruction.
|
||||||
fn trace_executed(&mut self, _gas_used: U256, _stack_push: &[U256], _mem_diff: Option<(usize, &[u8])>, _store_diff: Option<(U256, U256)>) {}
|
fn trace_executed(&mut self, _gas_used: U256, _stack_push: &[U256], _mem_diff: Option<(usize, &[u8])>, _store_diff: Option<(U256, U256)>) {}
|
||||||
|
|
||||||
/// Spawn subtracer which will be used to trace deeper levels of execution.
|
/// Spawn subtracer which will be used to trace deeper levels of execution.
|
||||||
fn prepare_subtrace(&self, code: &[u8]) -> Self where Self: Sized;
|
fn prepare_subtrace(&self, code: &[u8]) -> Self where Self: Sized;
|
||||||
|
|
||||||
/// Finalize subtracer.
|
/// Finalize subtracer.
|
||||||
fn done_subtrace(&mut self, sub: Self, is_successful: bool) where Self: Sized;
|
fn done_subtrace(&mut self, sub: Self) where Self: Sized;
|
||||||
|
|
||||||
/// Consumes self and returns the VM trace.
|
/// Consumes self and returns the VM trace.
|
||||||
fn drain(self) -> Option<VMTrace>;
|
fn drain(self) -> Option<VMTrace>;
|
||||||
|
@ -71,18 +71,15 @@ impl Tracer for NoopTracer {
|
|||||||
pub struct NoopVMTracer;
|
pub struct NoopVMTracer;
|
||||||
|
|
||||||
impl VMTracer for NoopVMTracer {
|
impl VMTracer for NoopVMTracer {
|
||||||
/// Trace the preparation to execute a single instruction.
|
fn trace_next_instruction(&mut self, _pc: usize, _instruction: u8) -> bool { false }
|
||||||
fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _gas_cost: &U256) -> bool { false }
|
|
||||||
|
fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _gas_cost: U256) {}
|
||||||
|
|
||||||
/// Trace the finalised execution of a single instruction.
|
|
||||||
fn trace_executed(&mut self, _gas_used: U256, _stack_push: &[U256], _mem_diff: Option<(usize, &[u8])>, _store_diff: Option<(U256, U256)>) {}
|
fn trace_executed(&mut self, _gas_used: U256, _stack_push: &[U256], _mem_diff: Option<(usize, &[u8])>, _store_diff: Option<(U256, U256)>) {}
|
||||||
|
|
||||||
/// Spawn subtracer which will be used to trace deeper levels of execution.
|
|
||||||
fn prepare_subtrace(&self, _code: &[u8]) -> Self { NoopVMTracer }
|
fn prepare_subtrace(&self, _code: &[u8]) -> Self { NoopVMTracer }
|
||||||
|
|
||||||
/// Spawn subtracer which will be used to trace deeper levels of execution.
|
fn done_subtrace(&mut self, _sub: Self) {}
|
||||||
fn done_subtrace(&mut self, _sub: Self, _is_successful: bool) {}
|
|
||||||
|
|
||||||
/// Consumes self and returns all VM traces.
|
|
||||||
fn drain(self) -> Option<VMTrace> { None }
|
fn drain(self) -> Option<VMTrace> { None }
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,8 @@ pub enum Error {
|
|||||||
Internal,
|
Internal,
|
||||||
/// When execution tries to modify the state in static context
|
/// When execution tries to modify the state in static context
|
||||||
MutableCallInStaticContext,
|
MutableCallInStaticContext,
|
||||||
|
/// Wasm error
|
||||||
|
Wasm,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a EvmError> for Error {
|
impl<'a> From<&'a EvmError> for Error {
|
||||||
@ -53,6 +55,7 @@ impl<'a> From<&'a EvmError> for Error {
|
|||||||
EvmError::StackUnderflow { .. } => Error::StackUnderflow,
|
EvmError::StackUnderflow { .. } => Error::StackUnderflow,
|
||||||
EvmError::OutOfStack { .. } => Error::OutOfStack,
|
EvmError::OutOfStack { .. } => Error::OutOfStack,
|
||||||
EvmError::BuiltIn { .. } => Error::BuiltIn,
|
EvmError::BuiltIn { .. } => Error::BuiltIn,
|
||||||
|
EvmError::Wasm { .. } => Error::Wasm,
|
||||||
EvmError::Internal(_) => Error::Internal,
|
EvmError::Internal(_) => Error::Internal,
|
||||||
EvmError::MutableCallInStaticContext => Error::MutableCallInStaticContext,
|
EvmError::MutableCallInStaticContext => Error::MutableCallInStaticContext,
|
||||||
}
|
}
|
||||||
@ -75,6 +78,7 @@ impl fmt::Display for Error {
|
|||||||
StackUnderflow => "Stack underflow",
|
StackUnderflow => "Stack underflow",
|
||||||
OutOfStack => "Out of stack",
|
OutOfStack => "Out of stack",
|
||||||
BuiltIn => "Built-in failed",
|
BuiltIn => "Built-in failed",
|
||||||
|
Wasm => "Wasm runtime error",
|
||||||
Internal => "Internal error",
|
Internal => "Internal error",
|
||||||
MutableCallInStaticContext => "Mutable Call In Static Context",
|
MutableCallInStaticContext => "Mutable Call In Static Context",
|
||||||
};
|
};
|
||||||
@ -94,6 +98,7 @@ impl Encodable for Error {
|
|||||||
Internal => 5,
|
Internal => 5,
|
||||||
BuiltIn => 6,
|
BuiltIn => 6,
|
||||||
MutableCallInStaticContext => 7,
|
MutableCallInStaticContext => 7,
|
||||||
|
Wasm => 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
s.append_internal(&value);
|
s.append_internal(&value);
|
||||||
@ -113,6 +118,7 @@ impl Decodable for Error {
|
|||||||
5 => Ok(Internal),
|
5 => Ok(Internal),
|
||||||
6 => Ok(BuiltIn),
|
6 => Ok(BuiltIn),
|
||||||
7 => Ok(MutableCallInStaticContext),
|
7 => Ok(MutableCallInStaticContext),
|
||||||
|
8 => Ok(Wasm),
|
||||||
_ => Err(DecoderError::Custom("Invalid error type")),
|
_ => Err(DecoderError::Custom("Invalid error type")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Verification queue info types
|
//! Verification queue info types
|
||||||
|
|
||||||
/// Verification queue status
|
/// Verification queue status
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
#[cfg_attr(feature = "ipc", binary)]
|
#[cfg_attr(feature = "ipc", binary)]
|
||||||
pub struct VerificationQueueInfo {
|
pub struct VerificationQueueInfo {
|
||||||
/// Number of queued items pending verification
|
/// Number of queued items pending verification
|
||||||
|
@ -132,12 +132,17 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut verified = HashSet::new();
|
||||||
for uncle in UntrustedRlp::new(bytes).at(2)?.iter().map(|rlp| rlp.as_val::<Header>()) {
|
for uncle in UntrustedRlp::new(bytes).at(2)?.iter().map(|rlp| rlp.as_val::<Header>()) {
|
||||||
let uncle = uncle?;
|
let uncle = uncle?;
|
||||||
if excluded.contains(&uncle.hash()) {
|
if excluded.contains(&uncle.hash()) {
|
||||||
return Err(From::from(BlockError::UncleInChain(uncle.hash())))
|
return Err(From::from(BlockError::UncleInChain(uncle.hash())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if verified.contains(&uncle.hash()) {
|
||||||
|
return Err(From::from(BlockError::DuplicateUncle(uncle.hash())))
|
||||||
|
}
|
||||||
|
|
||||||
// m_currentBlock.number() - uncle.number() m_cB.n - uP.n()
|
// m_currentBlock.number() - uncle.number() m_cB.n - uP.n()
|
||||||
// 1 2
|
// 1 2
|
||||||
// 2
|
// 2
|
||||||
@ -180,6 +185,7 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &
|
|||||||
|
|
||||||
verify_parent(&uncle, &uncle_parent)?;
|
verify_parent(&uncle, &uncle_parent)?;
|
||||||
engine.verify_block_family(&uncle, &uncle_parent, Some(bytes))?;
|
engine.verify_block_family(&uncle, &uncle_parent, Some(bytes))?;
|
||||||
|
verified.insert(uncle.hash());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -568,6 +574,11 @@ mod tests {
|
|||||||
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &bad_uncles), engine, &bc),
|
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &bad_uncles), engine, &bc),
|
||||||
TooManyUncles(OutOfBounds { max: Some(engine.maximum_uncle_count()), min: None, found: bad_uncles.len() }));
|
TooManyUncles(OutOfBounds { max: Some(engine.maximum_uncle_count()), min: None, found: bad_uncles.len() }));
|
||||||
|
|
||||||
|
header = good.clone();
|
||||||
|
bad_uncles = vec![ good_uncle1.clone(), good_uncle1.clone() ];
|
||||||
|
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &bad_uncles), engine, &bc),
|
||||||
|
DuplicateUncle(good_uncle1.hash()));
|
||||||
|
|
||||||
// TODO: some additional uncle checks
|
// TODO: some additional uncle checks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,13 +81,18 @@ impl vm::Informant for Informant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl trace::VMTracer for Informant {
|
impl trace::VMTracer for Informant {
|
||||||
fn trace_prepare_execute(&mut self, pc: usize, instruction: u8, gas_cost: &U256) -> bool {
|
fn trace_next_instruction(&mut self, pc: usize, instruction: u8) -> bool {
|
||||||
self.pc = pc;
|
self.pc = pc;
|
||||||
self.instruction = instruction;
|
self.instruction = instruction;
|
||||||
self.gas_cost = *gas_cost;
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn trace_prepare_execute(&mut self, pc: usize, instruction: u8, gas_cost: U256) {
|
||||||
|
self.pc = pc;
|
||||||
|
self.instruction = instruction;
|
||||||
|
self.gas_cost = gas_cost;
|
||||||
|
}
|
||||||
|
|
||||||
fn trace_executed(&mut self, gas_used: U256, stack_push: &[U256], mem_diff: Option<(usize, &[u8])>, store_diff: Option<(U256, U256)>) {
|
fn trace_executed(&mut self, gas_used: U256, stack_push: &[U256], mem_diff: Option<(usize, &[u8])>, store_diff: Option<(U256, U256)>) {
|
||||||
let info = evm::INSTRUCTIONS[self.instruction as usize];
|
let info = evm::INSTRUCTIONS[self.instruction as usize];
|
||||||
|
|
||||||
@ -127,17 +132,9 @@ impl trace::VMTracer for Informant {
|
|||||||
vm
|
vm
|
||||||
}
|
}
|
||||||
|
|
||||||
fn done_subtrace(&mut self, mut sub: Self, is_successful: bool) where Self: Sized {
|
fn done_subtrace(&mut self, mut sub: Self) {
|
||||||
if sub.depth == 1 {
|
if sub.depth == 1 {
|
||||||
// print last line with final state:
|
// print last line with final state:
|
||||||
if is_successful {
|
|
||||||
sub.pc += 1;
|
|
||||||
sub.instruction = 0;
|
|
||||||
} else {
|
|
||||||
let push_bytes = evm::push_bytes(sub.instruction);
|
|
||||||
sub.pc += if push_bytes > 0 { push_bytes + 1 } else { 0 };
|
|
||||||
sub.instruction = if sub.pc < sub.code.len() { sub.code[sub.pc] } else { 0 };
|
|
||||||
}
|
|
||||||
sub.gas_cost = 0.into();
|
sub.gas_cost = 0.into();
|
||||||
let gas_used = sub.gas_used;
|
let gas_used = sub.gas_used;
|
||||||
trace::VMTracer::trace_executed(&mut sub, gas_used, &[], None, None);
|
trace::VMTracer::trace_executed(&mut sub, gas_used, &[], None, None);
|
||||||
|
@ -44,6 +44,6 @@ impl vm::Informant for Informant {
|
|||||||
|
|
||||||
impl trace::VMTracer for Informant {
|
impl trace::VMTracer for Informant {
|
||||||
fn prepare_subtrace(&self, _code: &[u8]) -> Self where Self: Sized { Default::default() }
|
fn prepare_subtrace(&self, _code: &[u8]) -> Self where Self: Sized { Default::default() }
|
||||||
fn done_subtrace(&mut self, _sub: Self, _is_successful: bool) where Self: Sized {}
|
fn done_subtrace(&mut self, _sub: Self) {}
|
||||||
fn drain(self) -> Option<trace::VMTrace> { None }
|
fn drain(self) -> Option<trace::VMTrace> { None }
|
||||||
}
|
}
|
||||||
|
@ -134,10 +134,10 @@ impl Args {
|
|||||||
Ok(match self.flag_spec {
|
Ok(match self.flag_spec {
|
||||||
Some(ref filename) => {
|
Some(ref filename) => {
|
||||||
let file = fs::File::open(filename).map_err(|e| format!("{}", e))?;
|
let file = fs::File::open(filename).map_err(|e| format!("{}", e))?;
|
||||||
spec::Spec::load(file)?
|
spec::Spec::load(::std::env::temp_dir(), file)?
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
spec::Spec::new_instant()
|
ethcore::ethereum::new_foundation(&::std::env::temp_dir())
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -124,6 +124,7 @@
|
|||||||
"istanbul": "1.0.0-alpha.2",
|
"istanbul": "1.0.0-alpha.2",
|
||||||
"jsdom": "9.11.0",
|
"jsdom": "9.11.0",
|
||||||
"json-loader": "0.5.4",
|
"json-loader": "0.5.4",
|
||||||
|
"markdown-loader": "2.0.0",
|
||||||
"mocha": "3.2.0",
|
"mocha": "3.2.0",
|
||||||
"mock-local-storage": "1.0.2",
|
"mock-local-storage": "1.0.2",
|
||||||
"mock-socket": "6.0.4",
|
"mock-socket": "6.0.4",
|
||||||
|
@ -94,6 +94,7 @@ class FrameSecureApi extends SecureApi {
|
|||||||
const transport = window.secureTransport || new FakeTransport();
|
const transport = window.secureTransport || new FakeTransport();
|
||||||
const uiUrl = transport.uiUrl || 'http://127.0.0.1:8180';
|
const uiUrl = transport.uiUrl || 'http://127.0.0.1:8180';
|
||||||
|
|
||||||
|
transport.uiUrlWithProtocol = uiUrl;
|
||||||
transport.uiUrl = uiUrl.replace('http://', '').replace('https://', '');
|
transport.uiUrl = uiUrl.replace('http://', '').replace('https://', '');
|
||||||
const api = new FrameSecureApi(transport);
|
const api = new FrameSecureApi(transport);
|
||||||
|
|
||||||
|
@ -14,6 +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 { observer } from 'mobx-react';
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
@ -21,6 +22,7 @@ import { Form, Input, InputAddress, QrScan } from '~/ui';
|
|||||||
|
|
||||||
import ChangeVault from '../ChangeVault';
|
import ChangeVault from '../ChangeVault';
|
||||||
|
|
||||||
|
@observer
|
||||||
export default class NewQr extends Component {
|
export default class NewQr extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
createStore: PropTypes.object.isRequired,
|
createStore: PropTypes.object.isRequired,
|
||||||
|
@ -16,10 +16,17 @@
|
|||||||
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
import ReactMarkdown from 'react-markdown';
|
||||||
import { Checkbox } from 'material-ui';
|
import { Checkbox } from 'material-ui';
|
||||||
|
|
||||||
import styles from '../firstRun.css';
|
import styles from '../firstRun.css';
|
||||||
|
|
||||||
|
let tnc = '';
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV !== 'test') {
|
||||||
|
tnc = require('./tnc.md');
|
||||||
|
}
|
||||||
|
|
||||||
export default class TnC extends Component {
|
export default class TnC extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
hasAccepted: PropTypes.bool.isRequired,
|
hasAccepted: PropTypes.bool.isRequired,
|
||||||
@ -31,139 +38,10 @@ export default class TnC extends Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.tnc }>
|
<div className={ styles.tnc }>
|
||||||
<h1>SECURITY WARNINGS</h1>
|
<ReactMarkdown
|
||||||
<ul>
|
className={ styles.markdown }
|
||||||
<li>You are responsible for your own computer security. If your machine is compromised you will lose your ether, access to any contracts and maybe more.</li>
|
source={ tnc }
|
||||||
<li>You are responsible for your own actions. If you mess something up or break any laws while using this software, it is your fault, and your fault only.</li>
|
/>
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h1>LEGAL WARNING</h1>
|
|
||||||
<h2>SHORT VERSION</h2>
|
|
||||||
<h3>Disclaimer of Liability and Warranties</h3>
|
|
||||||
<ul>
|
|
||||||
<li>The user expressly knows and agrees that the user is using Parity at the user’s sole risk.</li>
|
|
||||||
<li>The user represents that the user has an adequate understanding of the risks, usage and intricacies of cryptographic tokens and blockchain-based open source software, eth platform and eth.</li>
|
|
||||||
<li>The user acknowledges and agrees that, to the fullest extent permitted by any applicable law, the disclaimers of liability contained herein apply to any and all damages or injury whatsoever caused by or related to risks of, use of, or inability to use, Parity under any cause or action whatsoever of any kind in any jurisdiction, including, without limitation, actions for breach of warranty, breach of contract or tort (including negligence) and that Eth Core Limited shall be not liable for any indirect, incidental, special, exemplary or consequential damages, including for loss of profits, goodwill or data.</li>
|
|
||||||
<li>Some jurisdictions do not allow the exclusion of certain warranties or the limitation or exclusion of liability for certain types of damages. Therefore, some of the above limitations in this section may not apply to a user. In particular, nothing in these terms shall affect the statutory rights of any user or exclude injury arising from any wilful misconduct or fraud of Eth Core Limited.</li>
|
|
||||||
<li>All rights reserved by Parity. Licensed to the public under the GPL v3 <a href='https://www.gnu.org/licenses/gpl-3.0.txt' target='_blank'>https://www.gnu.org/licenses/gpl-3.0.txt</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h2>LONG VERSION</h2>
|
|
||||||
<p>The following Terms and Conditions (“Terms”) govern the use of Parity Technologies Limited’s open source software product (“Parity”). Prior to any use of the Parity or any of Parity Technologies Limited’s products (“Parity’s Products”), the user or anyone on whose behalf the software is used for directly or indirectly (“User”) confirms that they understand and expressly agree to all of the Terms. All capitalized terms in this agreement will be given the same effect and meaning as in the Terms. The group of developers and other personnel that is now, or will be, employed by, or contracted with, or affiliated with, Parity Technologies Limited (“Parity”) is termed the “Parity Team”.</p>
|
|
||||||
|
|
||||||
<h3>Acknowledgement of Risks</h3>
|
|
||||||
<p>The user acknowledges the following serious risks to any use Parity and expressly agrees not to hold liable Parity or the Parity Team should any of these risks occur:</p>
|
|
||||||
|
|
||||||
<h3>Risk of Security Weaknesses in the Parity Core Infrastructure Software</h3>
|
|
||||||
<p>Parity rests on open-source software, and although it is professionally developed in line with industry standards (which include external audits of the code base), there is a risk that Parity or the Parity Team, may have introduce unintentional weaknesses or bugs into the core infrastructural elements of Parity causing the system to lose ETH stored in one or more User accounts or other accounts or lose sums of other valued tokens.</p>
|
|
||||||
|
|
||||||
<h3>Risk of Weaknesses or Exploitable Breakthroughs in the Field of Cryptography</h3>
|
|
||||||
<p>Cryptography is an art, not a science. And the state of the art can advance over time Advances in code cracking, or technical advances such as the development of quantum computers, could present risks to cryptocurrencies and Parity, which could result in the theft or loss of ETH. To the extent possible, Parity intends to update the protocol underlying Parity to account for any advances in cryptography and to incorporate additional security measures, but it cannot predict the future of cryptography or guaranty that any security updates will be made, timely or successful.</p>
|
|
||||||
|
|
||||||
<h3>Risk of Ether Mining Attacks</h3>
|
|
||||||
<p>As with other cryptocurrencies, the blockchain used by Parity is susceptible to mining attacks, including but not limited to double-spend attacks, majority mining power attacks, “selfish-mining” attacks, and race condition attacks. Any successful attacks present a risk to the Ethereum ecosystem, expected proper execution and sequencing of ETH transactions, and expected proper execution and sequencing of contract computations. Despite the efforts of the Parity and the Parity Team, known or novel mining attacks may be successful.</p>
|
|
||||||
|
|
||||||
<h3>Risk of Rapid Adoption and Insufficiency of Computational Application Processing Power on the Ethereum Network</h3>
|
|
||||||
<p>If Parity is rapidly adopted, the demand for transaction processing and decentralized application computations could rise dramatically and at a pace that exceeds the rate with which ETH miners can bring online additional mining power. Under such a scenario, the entire Ethereum ecosystem could become destabilized, due to the increased cost of running decentralized applications. In turn, this could dampen interest in the Ethereum ecosystem and ETH. Insufficiency of computational resources and an associated rise in the price of ETH could result in businesses being unable to acquire scarce computational resources to run their decentralized applications. This would represent revenue losses to businesses or worst case, cause businesses to cease operations because such operations have become uneconomical due to distortions in the crypto-economy.</p>
|
|
||||||
|
|
||||||
<h3>Risk of temporary network incoherence</h3>
|
|
||||||
<p>We recommend any groups handling large or important transactions to maintain a voluntary 24 hour waiting period on any ether deposited. In case the integrity of the network is at risk due to issues in the clients, we will endeavour to publish patches in a timely fashion to address the issues. We will endeavour to provide solutions within the voluntary 24 hour waiting period.</p>
|
|
||||||
|
|
||||||
<h3>Use of Parity by you</h3>
|
|
||||||
<p>You agree to use Parity only for purposes that are permitted by (a) these Terms and (b) any applicable law, regulation or generally accepted practices or guidelines in the relevant jurisdictions (including any laws regarding the export of data or software to and from the United Kingdom or other relevant countries).</p>
|
|
||||||
<p>You agree that you will not engage in any activity that interferes with or disrupts Parity’s or Parity’s Products’ functioning (or the networks which are connected to Parity).</p>
|
|
||||||
<p>Unless you have been specifically permitted to do so in a separate agreement with Parity, you agree that you will not reproduce, duplicate, copy, sell, trade or resell the Parity’s Products for any purpose unless than in accordance to the terms of the software licence terms available here: <a href='https://www.gnu.org/licenses/gpl-3.0.txt' target='_blank'>https://www.gnu.org/licenses/gpl-3.0.txt</a> (“Software Licence Terms”).</p>
|
|
||||||
<p>You agree that you are solely responsible for (and that Parity has no responsibility to you or to any third party for) any breach of your obligations under these terms and for the consequences (including any loss or damage which Parity may suffer) of any such breach.</p>
|
|
||||||
|
|
||||||
<h3>Privacy and your personal information</h3>
|
|
||||||
<p>You agree to the use of your data (if any is gathered) in accordance with Parity’s privacy policies: <a href='https://parity.io/legal.html' target='_blank'>https://parity.io/legal.html</a>. This policy explains how Parity treats your personal information (if any is gathered), and protects your privacy, when you use Parity’s Products.</p>
|
|
||||||
|
|
||||||
<h3>Content in Parity</h3>
|
|
||||||
<p>You understand that all information and data (such as smart contracts, data files, written text, computer software, music, audio files or other sounds, photographs, videos or other images) which you may have access to as part of, or through your use of, Parity’s Product are the sole responsibility of the person from which such content originated. All such information is referred to below as the “Content”.</p>
|
|
||||||
<p>You should be aware that Content presented to you through Parity or Parity’s Product may be protected by intellectual property rights which are owned by thisrd parties who may provide that Content to Parity (or by other persons or companies on their behalf). You may not modify, rent, lease, loan, sell, distribute or create derivative works based on this Content (either in whole or in part) unless you have been specifically told that you may do so by Parity or by the owners of that Content, in a separate agreement.</p>
|
|
||||||
<p>You understand that by using Parity or Parity’s Products you may be exposed to Content that you may find offensive, indecent or objectionable and that, in this respect, you use Parity or Parity’s Products at your own risk.</p>
|
|
||||||
<p>You agree that you are solely responsible for (and that Parity has no responsibility to you or to any third party for) any Content that you create, transmit or display while using Parity or Parity’s Products and for the consequences of your actions (including any loss or damage which Parity may suffer) by doing so.</p>
|
|
||||||
|
|
||||||
<h3>Proprietary rights</h3>
|
|
||||||
<p>You acknowledge and agree that Parity own all legal right, title and interest in and to the Parity and Parity’s Products, including any intellectual property rights which subsist in Parity and Parity’s Products (whether those rights happen to be registered or not, and wherever in the world those rights may exist).</p>
|
|
||||||
<p>Unless you have agreed otherwise in writing with Parity, nothing in the Terms gives you a right to use any of Parity’s trade names, trade marks, service marks, logos, domain names, and other distinctive brand features.</p>
|
|
||||||
<p>If you have been given an explicit right to use any of these brand features in a separate written agreement with Parity, then you agree that your use of such features shall be in compliance with that agreement, any applicable provisions of these terms, and Parity’s brand feature use guidelines as updated from time to time. These guidelines can be viewed online at <a href='https://parity.io/press.html' target='_blank'>https://parity.io/press.html</a>.</p>
|
|
||||||
<p>Parity acknowledges and agrees that it obtains no right, title or interest from you (or your licensors) under these terms in or to any content that you submit, post, transmit or display on, or through, Parity, including any intellectual property rights which subsist in that content (whether those rights happen to be registered or not, and wherever in the world those rights may exist). Unless you have agreed otherwise in writing with Parity, you agree that you are responsible for protecting and enforcing those rights and that Parity has no obligation to do so on your behalf.</p>
|
|
||||||
<p>You agree that you shall not remove, obscure, or alter any proprietary rights notices (including copyright and trade mark notices) which may be affixed to or contained within Parity or Parity’s Products.</p>
|
|
||||||
<p>Unless you have been expressly authorized to do so in writing by Parity, you agree that in using Parity, you will not use any trade mark, service mark, trade name, logo of any company or organization in a way that is likely or intended to cause confusion about the owner or authorized user of such marks, names or logos.</p>
|
|
||||||
|
|
||||||
<h3>License Restrictions from Parity</h3>
|
|
||||||
<p>You may not (and you may not permit anyone else to) copy, modify, create a derivative work of, reverse engineer, decompile or otherwise attempt to extract the source code of the Parity, Parity’s Products or any part thereof, unless this is expressly permitted by our Software Licence Terms or required by law, or unless you have been specifically told that you may do so by Parity, in writing.</p>
|
|
||||||
<p>Unless Parity has given you specific written permission to do so, you may not assign (or grant a sub-licence of) your rights to use Parity’s Products, grant a security interest in or over your rights to use the Parity’s Products, or otherwise transfer any part of your rights to use the Parity’s Products.</p>
|
|
||||||
|
|
||||||
<h3>Content licence from you</h3>
|
|
||||||
<p>You retain copyright and any other rights you already hold in content which you submit, post or display on or through, Parity.</p>
|
|
||||||
|
|
||||||
<h3>Ending your relationship with Parity</h3>
|
|
||||||
<p>The Terms will continue to apply until terminated by either you or Parity as set out below.</p>
|
|
||||||
<p>Parity may at any time, terminate its legal agreement with you if:</p>
|
|
||||||
<ol>
|
|
||||||
<li>you have breached any provision of these Terms (or have acted in manner which clearly shows that you do not intend to, or are unable to comply with the provisions of these terms); or</li>
|
|
||||||
<li>Parity is required to do so by law (for example, where the provision of Parity’s Product to you is, or becomes, unlawful); or</li>
|
|
||||||
<li>the partner with whom Parity offered products or services to you has terminated its relationship with Parity or ceased to offer products or services to you; or</li>
|
|
||||||
<li>Parity is transitioning to no longer providing products or services to users in the country in which you are resident or from which you use the service; or</li>
|
|
||||||
<li>the provision of products or services to you by Parity is, in Parity’s opinion, no longer commercially viable.</li>
|
|
||||||
<li>When these Terms come to an end, all of the legal rights, obligations and liabilities that you and Parity have benefited from, been subject to (or which have accrued over time whilst the Terms have been in force) or which are expressed to continue indefinitely, shall be unaffected by this cessation, and the England and Wales jurisdiction choice shall continue to apply to such rights, obligations and liabilities indefinitely.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<h3>ACKNOWLEDGEMENT AND ACCEPTANCE OF ALL RISKS, EXCLUSION OF WARRANTIES</h3>
|
|
||||||
<p>THE USER EXPRESSLY KNOWS AND AGREES THAT THE USER IS USING PARITY OR PARITY’S PRODUCTS AT THE USER’S SOLE RISK. THE USER REPRESENTS THAT THE USER HAS AN ADEQUATE UNDERSTANDING OF THE RISKS, USAGE AND INTRICACIES OF CRYPTOGRAPHIC TOKENS AND BLOCKCHAIN-BASED OPEN SOURCE SOFTWARE, PARITY.</p>
|
|
||||||
<p>YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR USE OF PARITY’S PRODUCTS IS AT YOUR SOLE RISK AND THAT PARITY’S PRODUCTS ARE PROVIDED "AS IS" AND “AS AVAILABLE.”</p>
|
|
||||||
<p>IN PARTICULAR, PARITY, ITS SUBSIDIARIES AND AFFILIATES, AND ITS LICENSORS DO NOT REPRESENT OR WARRANT TO YOU THAT:</p>
|
|
||||||
<p>(A) YOUR USE OF PARITY OR PARITY’S PRODUCTS WILL MEET YOUR REQUIREMENTS,</p>
|
|
||||||
<p>(B) YOUR USE OF PARITY OR PARITY’S PRODUCTS WILL BE UNINTERRUPTED, TIMELY, SECURE OR FREE FROM ERROR,</p>
|
|
||||||
<p>(C) ANY INFORMATION OBTAINED BY YOU AS A RESULT OF YOUR USE OF PARITY OR PARITY’S PRODUCTS WILL BE ACCURATE OR RELIABLE, AND</p>
|
|
||||||
<p>(D) THAT DEFECTS IN THE OPERATION OR FUNCTIONALITY OF ANY SOFTWARE PROVIDED TO YOU AS PART OF PARITY’S PRODUCTS WILL BE CORRECTED.</p>
|
|
||||||
<p>ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF PARITY OR PARITY’S PRODUCTS IS DONE AT YOUR OWN DISCRETION AND RISK AND THAT YOU WILL BE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR COMPUTER SYSTEM OR OTHER DEVICE OR LOSS OF DATA OR ECONOMIC LOSS THAT RESULTS FROM THE DOWNLOAD OF ANY SUCH MATERIAL.</p>
|
|
||||||
<p>NO ADVICE OR INFORMATION, WHETHER ORAL OR WRITTEN, OBTAINED BY YOU FROM PARITY OR THROUGH OR FROM PARITY’S PRODUCTS SHALL CREATE ANY WARRANTY NOT EXPRESSLY STATED IN THE TERMS.</p>
|
|
||||||
<p>PARITY FURTHER EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.</p>
|
|
||||||
|
|
||||||
<h3>EXCLUSION AND LIMITATION OF LIABILITY</h3>
|
|
||||||
<p>THE USER ACKNOWLEDGES AND AGREES THAT, TO THE FULLEST EXTENT PERMITTED BY ANY APPLICABLE LAW, THE DISCLAIMERS AND EXCLUSION OF LIABILITY CONTAINED HEREIN APPLY TO ANY AND ALL DAMAGES OR INJURY WHATSOEVER CAUSED BY OR RELATED TO RISKS OF, USE OF, OR INABILITY TO USE, PARITY UNDER ANY CAUSE OF ACTION WHATSOEVER OF ANY KIND IN ANY JURISDICTION, INCLUDING, WITHOUT LIMITATION, ACTIONS FOR BREACH OF WARRANTY, BREACH OF CONTRACT OR TORT (INCLUDING NEGLIGENCE) AND THAT NEITHER PARITY NOR THE PARITY TEAM SHALL BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES, INCLUDING FOR LOSS OF PROFITS, GOODWILL OR DATA.</p>
|
|
||||||
<p>SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF CERTAIN WARRANTIES OR THE LIMITATION OR EXCLUSION OF LIABILITY FOR CERTAIN TYPES OF DAMAGES. THEREFORE, SOME OF THE ABOVE LIMITATIONS IN THIS SECTION MAY NOT APPLY TO A USER. IN PARTICULAR, NOTHING IN THESE TERMS SHALL AFFECT THE STATUTORY RIGHTS OF ANY USER OR EXCLUDE INJURY ARISING FROM ANY WILLFUL MISCONDUCT OR FRAUD OF PARITY.</p>
|
|
||||||
<p>SUBJECT TO ANY LIABILITY WHICH MAY NOT BE EXCLUDED, YOU EXPRESSLY UNDERSTAND AND AGREE THAT PARITY, ITS SUBSIDIARIES AND AFFILIATES, AND ITS LICENSORS SHALL NOT BE LIABLE TO YOU FOR:</p>
|
|
||||||
<p>(A) ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL CONSEQUENTIAL OR EXEMPLARY DAMAGES WHICH MAY BE INCURRED BY YOU, HOWEVER CAUSED AND UNDER ANY THEORY OF LIABILITY. THIS SHALL INCLUDE, BUT NOT BE LIMITED TO, ANY LOSS OF PROFIT (WHETHER INCURRED DIRECTLY OR INDIRECTLY), ANY LOSS OF GOODWILL OR BUSINESS REPUTATION, ANY LOSS OF DATA SUFFERED, COST OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR OTHER INTANGIBLE LOSS;</p>
|
|
||||||
<p>(B) ANY LOSS OR DAMAGE WHICH MAY BE INCURRED BY YOU, INCLUDING BUT NOT LIMITED TO LOSS OR DAMAGE AS A RESULT OF:</p>
|
|
||||||
<p>(I) ANY RELIANCE PLACED BY YOU ON THE COMPLETENESS, ACCURACY OR EXISTENCE OF ANY ADVERTISING, OR AS A RESULT OF ANY RELATIONSHIP OR TRANSACTION BETWEEN YOU AND ANY ADVERTISER OR SPONSOR WHOSE ADVERTISING APPEARS ON PARITY’S PRODUCTS;</p>
|
|
||||||
<p>(II) ANY CHANGES WHICH PARITY MAY MAKE TO PARITY’S PRODUCTS, OR FOR ANY PERMANENT OR TEMPORARY CESSATION IN THE PROVISION OF PARITY’S PRODUCTS (OR ANY FEATURES WITHIN PARITY’S PRODUCTS);</p>
|
|
||||||
<p>(III) THE DELETION OF, CORRUPTION OF, OR FAILURE TO STORE, ANY CONTENT AND OTHER COMMUNICATIONS DATA MAINTAINED OR TRANSMITTED BY OR THROUGH YOUR USE OF PARITY’S PRODUCTS;</p>
|
|
||||||
<p>(IV) YOUR FAILURE TO PROVIDE PARITY WITH ACCURATE ACCOUNT INFORMATION (IF THIS IS REQUIRED);</p>
|
|
||||||
<p>(V) YOUR FAILURE TO KEEP YOUR PASSWORD OR ACCOUNT DETAILS SECURE AND CONFIDENTIAL;</p>
|
|
||||||
<p>THE LIMITATIONS ON PARITY’S LIABILITY TO YOU SHALL APPLY WHETHER OR NOT PARITY HAS BEEN ADVISED OF OR SHOULD HAVE BEEN AWARE OF THE POSSIBILITY OF ANY SUCH LOSSES ARISING.</p>
|
|
||||||
|
|
||||||
<h3>Copyright and trade mark policies</h3>
|
|
||||||
<p>It is Parity’s policy to respond to notices of alleged copyright infringement that comply with applicable international intellectual property law (including, in the United States, the Digital Millennium Copyright Act) and if Parity is put on notice and it is under Parity’s control and terminating the accounts of repeat infringers.</p>
|
|
||||||
|
|
||||||
<h3>Other content</h3>
|
|
||||||
<p>Services provided may include hyperlinks to other web sites, smart contracts or content or resources. Parity may have no control over any web sites or resources which are provided by companies or persons other than Parity.</p>
|
|
||||||
<p>You acknowledge and agree that Parity is not responsible for the availability of any such external sites or resources, and does not endorse any advertising, products or other materials on or available from such web sites or resources.</p>
|
|
||||||
<p>You acknowledge and agree that Parity is not liable for any loss or damage which may be incurred by you as a result of the availability of those external sites or resources, or as a result of any reliance placed by you on the completeness, accuracy or existence of any advertising, products or other materials on, or available from, such web sites or resources.</p>
|
|
||||||
|
|
||||||
<h3>Changes to the Terms</h3>
|
|
||||||
<p>Parity may make changes to these from time to time. When these changes are made, Parity will make a new copy of these terms available at https://parity.io/legal.html and any new terms will be made available to you from within, or through, the affected Parity’s Product.</p>
|
|
||||||
<p>You understand and agree that if you use Parity or Parity’s Products after the date on which the Terms have changed, Parity will treat your use as acceptance of the updated terms.</p>
|
|
||||||
|
|
||||||
<h3>General legal terms</h3>
|
|
||||||
<p>Sometimes when you use Parity or Parity’s Products, you may (as a result of, or in connection with your use of these products) use a service or download a piece of software, or smart contract, or purchase goods, which are provided by another person or company. Your use of these other services, software, smart contract or goods may be subject to separate terms between you and the company or person concerned. If so, these Terms do not affect your legal relationship with these other companies or individuals.</p>
|
|
||||||
<p>These Terms constitute the whole legal agreement between you and Parity and govern your use of Parity and Parity’s Products (but excluding any products or services which Parity may provide to you under a separate written agreement), and completely replace any prior agreements between you and Parity in relation to Parity and Parity’s Products.</p>
|
|
||||||
<p>You agree that Parity may provide you with notices, including those regarding changes to the Terms, by postings on the affected Parity’s Product.</p>
|
|
||||||
<p>You agree that if Parity does not exercise or enforce any legal right or remedy which is contained in these Terms (or which Parity has the benefit of under any applicable law), this will not be taken to be a formal waiver of Parity’s rights and that those rights or remedies will still be available to Parity.</p>
|
|
||||||
<p>If any court of law, having the jurisdiction to decide on this matter, rules that any provision of these Terms is invalid, then that provision will be removed from the Terms without affecting the rest of the Terms. The remaining provisions of the Terms will continue to be valid and enforceable.</p>
|
|
||||||
<p>You acknowledge and agree that each member of the group of companies of which Parity is the parent shall be third party beneficiaries to these Terms and that such other companies shall be entitled to directly enforce, and rely upon, any provision of the Terms which confers a benefit on (or rights in favor of) them. Other than this, no other person or company shall be third party beneficiaries to these Terms.</p>
|
|
||||||
<p>These Terms, and your relationship with Parity under these Terms, shall be governed by the laws of England and Wales, United Kingdom without regard to its conflict of laws provisions. You and Parity agree to submit to the exclusive jurisdiction of the courts located within England, United Kingdom to resolve any legal matter arising from these Terms (subject to the Dispute Resolution clause below). Notwithstanding this, you agree that Parity shall still be allowed to apply for injunctive remedies (or an equivalent type of urgent legal relief) in any jurisdiction.</p>
|
|
||||||
|
|
||||||
<h3>Dispute Resolution</h3>
|
|
||||||
<p>All disputes or claims arising out of, relating to, or in connection with the Terms, the breach thereof, or use of Parity shall be finally settled under the Rules of Arbitration of the International Chamber of Commerce by one or more arbitrators appointed in accordance with said Rules. All claims between the parties relating to these Terms that are capable of being resolved by arbitration, whether sounding in contract, tort, or otherwise, shall be submitted to ICC arbitration. Prior to commencing arbitration, the parties have a duty to negotiate in good faith and attempt to resolve their dispute in a manner other than by submission to ICC arbitration. The arbitration panel shall consist of one arbitrator only, unless the ICC Court of Arbitration determines that the dispute is such as to warrant three arbitrators. If the Court determines that one arbitrator is sufficient, then such arbitrator shall be a UK resident. If the Court determines that three arbitrators are necessary, then each party shall have 30 days to nominate an arbitrator of its choice - in the case of the Claimant, measured from receipt of notification of the ICC Court’s decision to have three arbitrators; in the case of Respondent, measured from receipt of notification of Claimant’s nomination. All nominations must be UK residents. If a party fails to nominate an arbitrator, the Court will do so. The Court shall also appoint the chairman. All arbitrators shall be and remain “independent” of the parties involved in the arbitration. The place of arbitration shall be England, United Kingdom. The language of the arbitration shall be English. In deciding the merits of the dispute, the tribunal shall apply the laws of England and Wales and any discovery shall be limited and shall not involve any depositions or any other examinations outside of a formal hearing. The tribunal shall not assume the powers of amiable compositeur or decide the case ex aequo et bono. In the final award, the tribunal shall fix the costs of the arbitration and decide which of the parties shall bear such costs in what proportion. Every award shall be binding on the parties. The parties undertake to carry out the award without delay and waive their right to any form of recourse against the award in so far as such waiver can validly be made.</p>
|
|
||||||
|
|
||||||
<h3>Additional Terms for Enterprise Use</h3>
|
|
||||||
<p>If you are a business entity, then the individual accepting on behalf of the entity (for the avoidance of doubt, for business entities, in these Terms, "you" means the entity) represents and warrants that he or she has the authority to act on your behalf, that you represent that you are duly authorized to do business in the country or countries where you operate, and that your employees, officers, representatives, and other agents accessing Parity’s Products are duly authorized to access Parity and to legally bind you to these Terms.</p>
|
|
||||||
<p>Subject to these Terms and subject to the Software Licence Terms, Parity grants you a non-exclusive, non-transferable licence to install and use Parity solely on machines intended for use by your employees, officers, representatives, and agents in connection with your business entity, and provided that their use of Parity will be subject to these Terms and Parity’s Products software licence terms.</p>
|
|
||||||
|
|
||||||
<Checkbox
|
<Checkbox
|
||||||
className={ styles.accept }
|
className={ styles.accept }
|
||||||
label={
|
label={
|
||||||
|
215
js/src/modals/FirstRun/TnC/tnc.md
Normal file
215
js/src/modals/FirstRun/TnC/tnc.md
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
# LEGAL WARNING SHORT VERSION
|
||||||
|
|
||||||
|
## Disclaimer of Liability and Warranties
|
||||||
|
|
||||||
|
- The user expressly acknowledges and agrees that Parity Technologies Limited makes the Parity client available to the user at the user's sole risk.
|
||||||
|
|
||||||
|
- The user represents that the user has an adequate understanding of the risks, usage and intricacies of cryptographic tokens and blockchain-based open source software, eth platform and eth.
|
||||||
|
|
||||||
|
- The user acknowledges and agrees that, to the fullest extent permitted by any applicable law, the disclaimers of liability contained herein apply to any and all damages or injury whatsoever caused by or related to risks of, use of, or inability to use, the Parity client under any cause or action whatsoever of any kind in any jurisdiction, including, without limitation, actions for breach of warranty, breach of contract or tort (including negligence) and that Parity Technologies Limited shall not be liable for any indirect, incidental, special, exemplary or consequential damages, including for loss of profits, goodwill or data.
|
||||||
|
|
||||||
|
- Some jurisdictions do not allow the exclusion of certain warranties or the limitation or exclusion of liability for certain types of damages. Therefore, some of the above limitations in this section may not apply to a user. In particular, nothing in these terms shall affect the statutory rights of any user or limit or exclude liability for death or physical injury arising from the negligence or wilful misconduct of Parity Technologies Limited or for fraud or fraudulent misrepresentation.
|
||||||
|
|
||||||
|
- All rights reserved by Parity Technologies Limited. Licensed to the public under the GPL v3: [https://www.gnu.org/licenses/gpl-3.0.txt](http://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
# LEGAL WARNING LONG VERSION
|
||||||
|
|
||||||
|
The following Terms and Conditions ("Terms") govern the use of Parity Technologies Limited's open source software product ("Parity"). Prior to any use of Parity or any of Parity Technologies Limited's products ("Parity Technologies' Products"), you ("User" or "you") confirm on your own behalf and on behalf of anyone who uses Parity on your behalf that you (and they) understand, expressly agree to and will comply with all of the Terms. All capitalized words and expressions in these Terms will have the effect and meaning given to them in the Terms. The group of developers and other personnel that is now, or will be, employed by, or contracted with, or affiliated with, Parity Technologies Limited ("Parity Technologies" or "we") is termed the "Parity Technologies Team".
|
||||||
|
|
||||||
|
## Acknowledgement of Risks
|
||||||
|
|
||||||
|
The User acknowledges the following serious risks to any use of Parity and expressly agrees not to hold liable Parity Technologies or the Parity Technologies Team should any of these risks occur:
|
||||||
|
|
||||||
|
## Risk of Security Weaknesses in the Parity Core Infrastructure Software
|
||||||
|
|
||||||
|
Parity uses open-source libraries and components developed by third parties. While Parity Technologies Limited generally aims to use only widely adopted open-source technology and develop it in line with industry standards, such open-source technology may contain bugs and errors and may not function correctly in all circumstances. As a result, there is a risk that Parity Technologies or the Parity Technologies Team may have introduced unintentional weaknesses or bugs into the core infrastructural elements of Parity causing the system to lose Ethereum tokens ("ETH") stored in one or more User accounts or other accounts or lose sums of other valued tokens.
|
||||||
|
|
||||||
|
## Risk of Weaknesses or Exploitable Breakthroughs in the Field of Cryptography
|
||||||
|
|
||||||
|
Cryptography is an art, not a science, and the state of the art can advance over time. Advances in code cracking, or technical advances such as the development of quantum computers, could present risks to cryptocurrencies and Parity, which could result in the theft or loss of ETH. To the extent possible, Parity Technologies intends to update the protocol underlying Parity to account for any advances in cryptography and to incorporate additional security measures, but it cannot predict the future of cryptography or guarantee that any security updates will be made, timely or successful.
|
||||||
|
|
||||||
|
## Risk of Ether Mining Attacks
|
||||||
|
|
||||||
|
As with other cryptocurrencies, the blockchain accessed by Parity is susceptible to mining attacks, including but not limited to double-spend attacks, majority mining power attacks, "selfish-mining" attacks, and race condition attacks. Any successful attacks present a risk to the Ethereum ecosystem, expected proper execution and sequencing of ETH transactions, and expected proper execution and sequencing of contract computations. Despite the efforts of Parity Technologies and the Parity Technologies Team, known or novel mining attacks may be successful.
|
||||||
|
|
||||||
|
## Risk of Rapid Adoption and Insufficiency of Computational Application Processing Power on the
|
||||||
|
|
||||||
|
## Ethereum Network
|
||||||
|
|
||||||
|
If Ethereum is rapidly adopted, the demand for transaction processing and distributed application computations could rise dramatically and at a pace that exceeds the rate with which ETH miners can bring online additional mining power. Under such a scenario, the entire Ethereum ecosystem could become destabilized, due to the increased cost of running distributed applications. In turn, this could dampen interest in the Ethereum ecosystem and ETH. Insufficiency of computational resources and an associated rise in the price of ETH could result in businesses being unable to acquire scarce computational resources to run their distributed applications. This would represent revenue losses to businesses or worst case, cause businesses to cease operations because such operations have become uneconomical due to distortions in the crypto-economy.
|
||||||
|
|
||||||
|
## Risk of temporary network incoherence
|
||||||
|
|
||||||
|
We recommend any groups handling large or important transactions to maintain a voluntary 24 hour waiting period on any ETH deposited. If we become aware that the integrity of the network is at risk due to issues with Parity, we will endeavour to publish patches in a timely fashion to address the issues. We will endeavour to provide solutions within the voluntary 24 hour waiting period.
|
||||||
|
|
||||||
|
## Use of Parity by you
|
||||||
|
|
||||||
|
You agree to use Parity only for purposes that are permitted by (a) these Terms (including the Software Licence Terms, as defined below) and (b) any applicable law or regulation in the relevant jurisdictions (including any laws regarding the export of data or software to and from the United Kingdom or other relevant countries).
|
||||||
|
|
||||||
|
You agree that you will not engage in any activity that: (1) interferes with or disrupts Parity's or Parity Technologies' Products' functioning (or the networks which are connected to Parity), or (2) is calculated or likely to do so.
|
||||||
|
|
||||||
|
Unless you have been specifically permitted to do so in a separate agreement with Parity Technologies, you agree that you will not reproduce, duplicate, copy, sell, trade or resell Parity or Parity Technologies' Products for any purpose unless than in accordance with the terms of the software licence terms available here: https [://www.gnu.org/licenses/gpl-3.0.txt](http://www.gnu.org/licenses/gpl-3.0.txt)("Software Licence Terms").
|
||||||
|
|
||||||
|
You agree that you are solely responsible for (and that Parity Technologies has no responsibility to you or to any third party for) any breach of your obligations under these Terms and for the consequences (including any loss or damage which Parity Technologies may suffer) of any such breach.
|
||||||
|
|
||||||
|
## Privacy and your personal information
|
||||||
|
|
||||||
|
You agree to the use of your data (if any is gathered) in accordance with Parity Technologies' privacy policies: [https://parity.io/legal.html](https://parity.io/legal.html). This policy explains how Parity Technologies treats your personal information (if any is gathered), and protects your privacy, when you use Parity Technologies' Products.
|
||||||
|
|
||||||
|
## Content in Parity
|
||||||
|
|
||||||
|
You understand that all information and data (such as smart contracts, data files, written text, computer software, music, audio files or other sounds, photographs, videos or other images) which you may have access to as part of, or through your use of, Parity or Parity Technologies' Products are the sole responsibility of the person from which such content originated. All such information is referred to below as "Content".
|
||||||
|
|
||||||
|
You should be aware that Content presented to you through Parity or Parity Technologies' Products, including but not limited to any advertisements and any sponsored Content within Parity, may be protected by intellectual property rights which are owned by the possible sponsors or advertisers who may provide that Content to Parity Technologies (or by other persons or companies on their behalf). You may not modify, rent, lease, loan, sell, distribute or create derivative works based on this Content (either in whole or in part) unless you have been specifically told that you may do so by Parity Technologies or by the owners of that Content, in a separate agreement.
|
||||||
|
|
||||||
|
Parity Technologies reserves the right (but shall have no obligation) to pre-screen, review, flag, filter, modify, refuse or remove any or all Content presented.
|
||||||
|
|
||||||
|
You understand that by using Parity or Parity Technologies' Products you may be exposed to Content that you may find offensive, indecent or objectionable and that, in this additional respect, you use Parity or Parity Technologies' Products at your own risk.
|
||||||
|
|
||||||
|
You agree that you are solely responsible for (and that Parity Technologies has no responsibility to you or to any third party for) any Content that you create, transmit or display while using Parity or Parity Technologies' Products and for the consequences of your actions (including any loss or damage which Parity Technologies may suffer) by doing so.
|
||||||
|
|
||||||
|
## Proprietary rights
|
||||||
|
|
||||||
|
You acknowledge and agree that Parity Technologies owns all legal right, title and interest in and to Parity and Parity Technologies' Products, including any intellectual property rights which subsist in Parity and Parity Technologies' Products (whether those rights happen to be registered or not, and wherever in the world those rights may exist).
|
||||||
|
|
||||||
|
Unless you have agreed otherwise in writing with Parity Technologies, nothing in the Terms gives you a right to use any of Parity Technologies' trade names, trade marks, service marks, logos, domain names, and other distinctive brand features.
|
||||||
|
|
||||||
|
If you have been given an explicit right to use any of these brand features in a separate written agreement with Parity Technologies, then you agree that your use of such features shall be in compliance with that agreement, any applicable provisions of these Terms, and Parity Technologies' brand feature use guidelines as updated from time to time. These guidelines can be viewed online at https://parity.io/press.html.
|
||||||
|
|
||||||
|
You retain copyright and any other rights you already hold in Content which you submit, post or display on or through, Parity. By posting Content, you grant to Parity Technologies a perpetual, royalty-free, non-exclusive, and irrevocable right and licence to use such Content in connection with its provision of Parity and Parity Technologies' Products. Parity Technologies acknowledges and agrees that, except as expressly provided in these Terms or the Software Licence Terms, it obtains no right, title or interest from you (or your licensors) in or to any Content that you submit, post, transmit or display on, or through, Parity, including any intellectual property rights which subsist in that Content (whether those rights happen to be registered or not, and wherever in the world those rights may exist). Unless you have agreed otherwise in writing with Parity Technologies, you agree that you are responsible for protecting and enforcing those rights and that Parity Technologies has no obligation to do so on your behalf.
|
||||||
|
|
||||||
|
You agree that you shall not remove, obscure, or alter any proprietary rights notices (including copyright and trade mark notices) which may be affixed to or contained within Parity or Parity Technologies' Products.
|
||||||
|
|
||||||
|
Unless you have been expressly authorized to do so in writing by Parity Technologies, you agree that in using Parity, you will not use any trade mark, service mark, trade name, logo of any company or organization in a way that is likely or intended to cause confusion about the owner or authorized user of such marks, names or logos.
|
||||||
|
|
||||||
|
## License Restrictions from Parity Technologies
|
||||||
|
|
||||||
|
You may not (and you may not permit anyone else to) copy, modify, create a derivative work of, reverse engineer, decompile or otherwise attempt to extract the source code of Parity, Parity Technologies' Products or any part thereof, unless this is expressly permitted by our Software Licence Terms or required by law, or unless you have been specifically told that you may do so by Parity Technologies, in writing.
|
||||||
|
|
||||||
|
Unless Parity Technologies has given you specific written permission to do so, you may not assign (or grant a sub- licence of) your rights to use Parity Technologies' Products, grant a security interest in or over your rights to use Parity Technologies' Products, or otherwise transfer any part of your rights to use Parity Technologies' Products.
|
||||||
|
|
||||||
|
## Software updates
|
||||||
|
|
||||||
|
Parity may automatically download and install updates from time to time from Parity Technologies. These updates are designed to improve, enhance and further develop Parity and may take the form of bug fixes, enhanced functions, new software modules and completely new versions. You agree to receive such updates (and permit Parity Technologies to deliver these to you) as part of your use of Parity and Parity Technologies' Products.
|
||||||
|
|
||||||
|
## Ending your relationship with Parity Technologies
|
||||||
|
|
||||||
|
The Terms will continue to apply until terminated by either you or Parity Technologies as set out below. You may at any time, terminate your legal agreement with Parity Technologies. Parity Technologies may at any time, terminate its legal agreement with you if:
|
||||||
|
|
||||||
|
(A) you have breached any provision of these Terms (or have acted in manner which indicates that you do not intend to, or are unable to comply with the provisions of these terms); or
|
||||||
|
|
||||||
|
(B) Parity Technologies is required to do so by law (for example, where the provision of Parity or any of Parity Technologies' Products to you is, or becomes, unlawful); or
|
||||||
|
|
||||||
|
(C) any partner with whom Parity Technologies offered products or services to you has terminated its relationship with Parity Technologies or ceased to offer products or services to you; or
|
||||||
|
|
||||||
|
(D) Parity Technologies is transitioning to no longer providing products or services to users in the country in which you are resident or from which you use the service; or
|
||||||
|
|
||||||
|
(E) the provision of products or services to you by Parity Technologies is, in Parity Technologies' opinion, no longer commercially viable.
|
||||||
|
|
||||||
|
When these Terms come to an end for any reason:
|
||||||
|
|
||||||
|
(A) you must immediately cease use of Parity and Parity Technologies' Products;
|
||||||
|
|
||||||
|
(B) you must delete or remove Parity or Parity Technologies' Products from all computer equipment in your possession or under your control; and
|
||||||
|
|
||||||
|
(C) all of the rights granted to you in these Terms shall cease.
|
||||||
|
|
||||||
|
Except as set out above, termination of these Terms shall not affect any rights, remedies, obligations and liabilities that have accrued to you or Parity Technologies up to the date of termination, including the right to claim damages in respect of any breach of these Terms which existed at or before the date of termination, and the courts of England and Wales shall continue to have jurisdiction in respect of such rights, obligations and liabilities indefinitely.
|
||||||
|
|
||||||
|
## Acknowledgement and acceptance of all risks, exclusion of warranties
|
||||||
|
|
||||||
|
The User expressly acknowledges and agrees that the User is using Parity and Parity Technologies' Products at the User's sole risk. The User represents that the User has an adequate understanding of the risks, usage and intricacies of cryptographic tokens and blockchain-based open source software.
|
||||||
|
|
||||||
|
You expressly understand and agree that Parity and Parity Technologies' Products are provided "as is" and "as available."
|
||||||
|
|
||||||
|
Parity Technologies, its subsidiaries and affiliates, and its licensors do not represent or warrant to you that:
|
||||||
|
|
||||||
|
(a) your use of Parity or Parity Technologies' Products will meet your requirements,
|
||||||
|
|
||||||
|
(b) your use of Parity or Parity Technologies' Products will be uninterrupted, timely, secure or free from error,
|
||||||
|
|
||||||
|
(c) any information obtained by you as a result of your use of Parity or Parity Technologies' Products will be accurate or reliable, or
|
||||||
|
|
||||||
|
(d) defects in the operation or functionality of any software provided to you as part of Parity Technologies' Products will be corrected.
|
||||||
|
|
||||||
|
Any material downloaded or otherwise obtained through the use of Parity or Parity Technologies' Products is done at your own discretion and risk and you will be solely responsible for any damage to your computer system or other device or loss of data or economic loss that results from the download of any such material.
|
||||||
|
|
||||||
|
No advice or information, whether oral or written, obtained by you from Parity Technologies or through or from Parity Technologies' Products shall create any warranty not expressly stated in the Terms.
|
||||||
|
|
||||||
|
To the fullest extent permitted by applicable law, Parity Technologies expressly disclaims all implied warranties and conditions of any kind including, but not limited to, implied statutory warranties and conditions of merchantability, fitness for a particular purpose and non-infringement.
|
||||||
|
|
||||||
|
## Exclusion and limitation of liability
|
||||||
|
|
||||||
|
The User acknowledges and agrees that, to the fullest extent permitted by any applicable law, the disclaimers and exclusion of liability contained herein apply to any and all damages or injury whatsoever caused by or related to risks of, use of, or inability to use, Parity under any cause of action whatsoever of any kind in any jurisdiction, including, without limitation, actions for breach of warranty, breach of contract or tort (including negligence).
|
||||||
|
|
||||||
|
Some jurisdictions do not allow the exclusion of certain warranties or the limitation or exclusion of liability for certain types of damages. Therefore, some of the above limitations in this section may not apply to you. In particular, nothing in these terms shall affect the statutory rights of any User or limit or exclude liability for death or physical injury arising from the negligence or wilful misconduct of Parity Technologies or for fraud or fraudulent misrepresentation.
|
||||||
|
|
||||||
|
Subject to any liability which may not be excluded, you expressly understand and agree that Parity Technologies, its subsidiaries and affiliates, and its licensors shall not be liable to you for:
|
||||||
|
|
||||||
|
(a) any direct, indirect, incidental, special consequential or exemplary damages which may be incurred by you, however caused and under any theory of liability. This shall include, but not be limited to, any loss of profit (whether incurred directly or indirectly), any loss of goodwill or business reputation, any loss of data suffered, cost of procurement of substitute goods or services, or other intangible loss; or
|
||||||
|
|
||||||
|
(b) any loss or damage which may be incurred by you, including but not limited to loss or damage as a result of:
|
||||||
|
|
||||||
|
(i) any reliance placed by you on the completeness, accuracy or existence of any advertising, or as a result of any relationship or transaction between you and any advertiser or sponsor whose advertising appears on Parity Technologies' Products;
|
||||||
|
|
||||||
|
(ii) any changes which Parity Technologies may make to Parity Technologies' Products, or for any permanent or temporary cessation in the provision of Parity Technologies' Products (or any features within Parity Technologies' Products);
|
||||||
|
|
||||||
|
(iii) the deletion of, corruption of, or failure to store, any content and other communications data maintained or transmitted by or through your use of Parity Technologies' Products;
|
||||||
|
|
||||||
|
(iv) your failure to provide Parity Technologies with accurate account information (if this is required); and
|
||||||
|
|
||||||
|
(v) your failure to keep your password or account details secure and confidential.
|
||||||
|
|
||||||
|
The limitations on Parity Technologies' liability to you shall apply whether or not Parity Technologies has been advised of or should have been aware of the possibility of any such losses arising.
|
||||||
|
|
||||||
|
## Copyright and trade mark policies
|
||||||
|
|
||||||
|
It is Parity Technologies' policy to respond to notices of alleged copyright infringement that comply with applicable international intellectual property law (including, in the United States, the Digital Millennium Copyright Act) where Parity Technologies is put on notice and it is under Parity Technologies' control. In such cases Parity Technologies shall be entitled to terminate the accounts of repeat infringers.
|
||||||
|
|
||||||
|
## Possible Advertisements
|
||||||
|
|
||||||
|
Products or services provided may be supported by advertising revenue and may display advertisements and promotions. These advertisements may be targeted to the content of information stored on products or services, queries made through the products or services or other information.
|
||||||
|
|
||||||
|
The manner, mode and extent of advertising by Parity Technologies on Parity Technologies' Products are subject to change without specific notice to you.
|
||||||
|
|
||||||
|
You agree that Parity Technologies may place such advertising on products and services accessed to you through Parity Technologies' products.
|
||||||
|
|
||||||
|
## Other content
|
||||||
|
|
||||||
|
Parity Technologies' services provided may include hyperlinks to other web sites, smart contracts or content or resources. Parity Technologies may have no control over any web sites or resources which are provided by companies or persons other than Parity Technologies.
|
||||||
|
|
||||||
|
You acknowledge and agree that Parity Technologies is not responsible for the availability of any such external sites or resources, and does not endorse any advertising, products or other materials on or available from such web sites or resources.
|
||||||
|
|
||||||
|
You acknowledge and agree that Parity Technologies is not liable for any loss or damage which may be incurred by you as a result of the availability of those external sites or resources, or as a result of any reliance placed by you on the completeness, accuracy or existence of any advertising, products or other materials on, or available from, such web sites or resources.
|
||||||
|
|
||||||
|
## Changes to the Terms
|
||||||
|
|
||||||
|
Parity Technologies may make changes to these Terms from time to time. When these changes are made, Parity Technologies will make a new copy of these Terms available at [https://parity.io/legal.html](https://parity.io/legal.html)and any new terms will be made available to you from within, or through, Parity or the affected Parity Technologies' Product.
|
||||||
|
|
||||||
|
You understand and agree that if you use Parity or Parity Technologies' Products after the date on which the Terms have changed, Parity Technologies will treat your use as acceptance of the updated terms.
|
||||||
|
|
||||||
|
## General legal terms
|
||||||
|
|
||||||
|
Sometimes when you use Parity or Parity Technologies' Products, you may (as a result of, or in connection with your use of these products) use a service or download a piece of software, or smart contract, or purchase goods, which are provided by another person or company. Your use of these other services, software, smart contract or goods may be subject to separate terms between you and the company or person concerned. If so, these Terms do not affect your legal relationship with these other companies or individuals.
|
||||||
|
|
||||||
|
These Terms (including the Software Licence Terms) constitute the whole legal agreement between you and Parity Technologies and govern your use of Parity and Parity Technologies' Products (but excluding any products or services which Parity Technologies may provide to you under a separate written agreement), and completely replace any prior agreements between you and Parity Technologies in relation to Parity and Parity Technologies' Products.
|
||||||
|
|
||||||
|
You agree that Parity Technologies may provide you with notices, including those regarding changes to the Terms, by postings on Parity or the affected Parity Technologies' Product.
|
||||||
|
|
||||||
|
You agree that if Parity Technologies does not exercise or enforce any legal right or remedy which is contained in these Terms (or which Parity Technologies has the benefit of under any applicable law), this will not be taken to be a formal waiver of Parity Technologies' rights and that those rights or remedies will still be available to Parity Technologies.
|
||||||
|
|
||||||
|
If any court of law, having the jurisdiction to decide on this matter, rules that any provision of these Terms is invalid, then that provision will be removed from the Terms without affecting the rest of the Terms. The remaining provisions of the Terms will continue to be valid and enforceable.
|
||||||
|
|
||||||
|
You acknowledge and agree that each member of the group of companies of which Parity Technologies is the parent shall be third party beneficiaries to these Terms and that such other companies shall be entitled to directly enforce, and rely upon, any provision of the Terms which confers a benefit on (or rights in favour of) them. Other than this, no other person or company shall be third party beneficiaries to these Terms.
|
||||||
|
|
||||||
|
These Terms, and your relationship with Parity Technologies under these Terms, shall be governed by the laws of England and Wales, United Kingdom. You and Parity Technologies agree to submit to the exclusive jurisdiction of the courts located within England, United Kingdom to resolve any legal matter arising from these Terms (subject to the Dispute Resolution clause below). Notwithstanding this, you agree that Parity Technologies shall still be allowed to apply for injunctive remedies (or an equivalent type of urgent legal relief) in any jurisdiction.
|
||||||
|
|
||||||
|
## Dispute Resolution
|
||||||
|
|
||||||
|
All disputes or claims arising out of, relating to, or in connection with the Terms, the breach thereof, or use of Parity shall be finally settled under the Rules of Arbitration of the International Chamber of Commerce by one or more arbitrators appointed in accordance with said Rules. All claims between the parties relating to these Terms that are capable of being resolved by arbitration, whether sounding in contract, tort, or otherwise, shall be submitted to ICC arbitration. Prior to commencing arbitration, the parties have a duty to negotiate in good faith and attempt to resolve their dispute in a manner other than by submission to ICC arbitration. The arbitration panel shall consist of one arbitrator only, unless the ICC Court of Arbitration determines that the dispute is such as to warrant three arbitrators. If the Court determines that one arbitrator is sufficient, then such arbitrator shall be a UK resident. If the Court determines that three arbitrators are necessary, then each party shall have 30 days to nominate an arbitrator of its choice - in the case of the Claimant, measured from receipt of notification of the ICC Court's decision to have three arbitrators; in the case of Respondent, measured from receipt of notification of Claimant's nomination. All nominations must be UK residents. If a party fails to nominate an arbitrator, the Court will do so. The Court shall also appoint the chairman. All arbitrators shall be and remain "independent" of the parties involved in the arbitration. The place of arbitration shall be England, United Kingdom. The language of the arbitration shall be English. In deciding the merits of the dispute, the tribunal shall apply the laws of England and Wales and any discovery shall be limited and shall not involve any depositions or any other examinations outside of a formal hearing. The tribunal shall not assume the powers of amiable compositeur or decide the case ex aequo et bono. In the final award, the tribunal shall fix the costs of the arbitration and decide which of the parties shall bear such costs in what proportion. Every award shall be binding on the parties. The parties undertake to carry out the award without delay and waive their right to any form of recourse against the award in so far as such waiver can validly be made. Notwithstanding the foregoing, either party shall be entitled at any time to apply to the courts of England, United Kingdom for injunctive relief, or where a claim is incapable of being resolved by arbitration.
|
||||||
|
|
||||||
|
## Additional Terms for Enterprise Use
|
||||||
|
|
||||||
|
If you are a business entity, then the individual accepting on behalf of the entity (for the avoidance of doubt, for business entities, in these Terms, "you" means the entity) represents and warrants that he or she has the authority to act on your behalf, that you represent that you are duly authorized to do business in the country or countries where you operate, and that your employees, officers, representatives, and other agents accessing Parity Technologies' Products are duly authorized to access Parity and to legally bind you to these Terms.
|
||||||
|
|
||||||
|
Subject to these Terms and subject to the Software Licence Terms, Parity Technologies grants you a non-exclusive, non-transferable licence to use Parity solely on machines intended for use by your employees, officers, representatives, and agents in connection with your business entity, and provided that their use of Parity Technologies will be subject to these Terms (including the Software Licence Terms).
|
@ -44,4 +44,7 @@
|
|||||||
.accept {
|
.accept {
|
||||||
margin: 1.5em 0;
|
margin: 1.5em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.markdown {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,10 @@ import { statusBlockNumber, statusCollection } from './statusActions';
|
|||||||
const log = getLogger(LOG_KEYS.Signer);
|
const log = getLogger(LOG_KEYS.Signer);
|
||||||
let instance = null;
|
let instance = null;
|
||||||
|
|
||||||
|
const STATUS_OK = 'ok';
|
||||||
|
const STATUS_WARN = 'needsAttention';
|
||||||
|
const STATUS_BAD = 'bad';
|
||||||
|
|
||||||
export default class Status {
|
export default class Status {
|
||||||
_apiStatus = {};
|
_apiStatus = {};
|
||||||
_status = {};
|
_status = {};
|
||||||
@ -195,13 +199,16 @@ export default class Status {
|
|||||||
|
|
||||||
const statusPromises = [
|
const statusPromises = [
|
||||||
this._api.eth.syncing(),
|
this._api.eth.syncing(),
|
||||||
this._api.parity.netPeers()
|
this._api.parity.netPeers(),
|
||||||
|
this._fetchHealth()
|
||||||
];
|
];
|
||||||
|
|
||||||
return Promise
|
return Promise
|
||||||
.all(statusPromises)
|
.all(statusPromises)
|
||||||
.then(([ syncing, netPeers ]) => {
|
.then(([ syncing, netPeers, health ]) => {
|
||||||
const status = { netPeers, syncing };
|
const status = { netPeers, syncing, health };
|
||||||
|
|
||||||
|
health.overall = this._overallStatus(health);
|
||||||
|
|
||||||
if (!isEqual(status, this._status)) {
|
if (!isEqual(status, this._status)) {
|
||||||
this._store.dispatch(statusCollection(status));
|
this._store.dispatch(statusCollection(status));
|
||||||
@ -216,6 +223,33 @@ export default class Status {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_overallStatus = (health) => {
|
||||||
|
const all = [health.peers, health.sync, health.time].filter(x => x);
|
||||||
|
const statuses = all.map(x => x.status);
|
||||||
|
const bad = statuses.find(x => x === STATUS_BAD);
|
||||||
|
const needsAttention = statuses.find(x => x === STATUS_WARN);
|
||||||
|
const message = all.map(x => x.message).filter(x => x);
|
||||||
|
|
||||||
|
if (all.length) {
|
||||||
|
return {
|
||||||
|
status: bad || needsAttention || STATUS_OK,
|
||||||
|
message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: STATUS_BAD,
|
||||||
|
message: ['Unable to fetch node health.']
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
_fetchHealth = () => {
|
||||||
|
// Support Parity-Extension.
|
||||||
|
const uiUrl = this._api.transport.uiUrlWithProtocol || '';
|
||||||
|
|
||||||
|
return fetch(`${uiUrl}/api/health`).then(res => res.json());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data fetched here should not change
|
* The data fetched here should not change
|
||||||
* unless Parity is restarted. They are thus
|
* unless Parity is restarted. They are thus
|
||||||
|
@ -18,11 +18,28 @@ import BigNumber from 'bignumber.js';
|
|||||||
import { handleActions } from 'redux-actions';
|
import { handleActions } from 'redux-actions';
|
||||||
|
|
||||||
const DEFAULT_NETCHAIN = '(unknown)';
|
const DEFAULT_NETCHAIN = '(unknown)';
|
||||||
|
const DEFAULT_STATUS = 'needsAttention';
|
||||||
const initialState = {
|
const initialState = {
|
||||||
blockNumber: new BigNumber(0),
|
blockNumber: new BigNumber(0),
|
||||||
blockTimestamp: new Date(),
|
blockTimestamp: new Date(),
|
||||||
clientVersion: '',
|
clientVersion: '',
|
||||||
gasLimit: new BigNumber(0),
|
gasLimit: new BigNumber(0),
|
||||||
|
health: {
|
||||||
|
peers: {
|
||||||
|
status: DEFAULT_STATUS
|
||||||
|
},
|
||||||
|
sync: {
|
||||||
|
status: DEFAULT_STATUS
|
||||||
|
},
|
||||||
|
time: {
|
||||||
|
status: DEFAULT_STATUS
|
||||||
|
},
|
||||||
|
overall: {
|
||||||
|
isReady: false,
|
||||||
|
status: DEFAULT_STATUS,
|
||||||
|
message: []
|
||||||
|
}
|
||||||
|
},
|
||||||
netChain: DEFAULT_NETCHAIN,
|
netChain: DEFAULT_NETCHAIN,
|
||||||
netPeers: {
|
netPeers: {
|
||||||
active: new BigNumber(0),
|
active: new BigNumber(0),
|
||||||
|
@ -31,7 +31,8 @@ export default class Actionbar extends Component {
|
|||||||
title: nodeOrStringProptype(),
|
title: nodeOrStringProptype(),
|
||||||
buttons: PropTypes.array,
|
buttons: PropTypes.array,
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
className: PropTypes.string
|
className: PropTypes.string,
|
||||||
|
health: PropTypes.node
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
|
17
js/src/ui/StatusIndicator/index.js
Normal file
17
js/src/ui/StatusIndicator/index.js
Normal 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 './statusIndicator';
|
88
js/src/ui/StatusIndicator/statusIndicator.css
Normal file
88
js/src/ui/StatusIndicator/statusIndicator.css
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/* 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/>.
|
||||||
|
*/
|
||||||
|
.status {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radial,.signal {
|
||||||
|
display: inline-block;
|
||||||
|
margin: .2em;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radial {
|
||||||
|
border-radius: 100%;
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.5);
|
||||||
|
background-image: radial-gradient(ellipse at top, rgba(255, 255, 255, 0.38) 0%, rgba(255, 255, 255, 0) 100%);
|
||||||
|
|
||||||
|
&.ok {
|
||||||
|
background-color: #070;
|
||||||
|
}
|
||||||
|
&.bad {
|
||||||
|
background-color: #c00;
|
||||||
|
}
|
||||||
|
&.needsAttention {
|
||||||
|
background-color: #dc0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.signal {
|
||||||
|
width: 2em;
|
||||||
|
width: calc(.9em + 5px);
|
||||||
|
text-transform: initial;
|
||||||
|
vertical-align: bottom;
|
||||||
|
margin-top: -1em;
|
||||||
|
|
||||||
|
> .bar {
|
||||||
|
display: inline-block;
|
||||||
|
border: 1px solid #444;
|
||||||
|
box-shadow: 0 0 1px rgba(0, 0, 0, 0.8);
|
||||||
|
width: .3em;
|
||||||
|
height: 1em;
|
||||||
|
opacity: 0.7;
|
||||||
|
background-color: rgba(0, 0, 0, 0.6);
|
||||||
|
vertical-align: bottom;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
opacity: 1.0;
|
||||||
|
background-image: linear-gradient(0, rgba(255, 255, 255, 0.38) 0%, rgba(255, 255, 255, 0) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bad {
|
||||||
|
height: .4em;
|
||||||
|
border-right: 0;
|
||||||
|
}
|
||||||
|
&.needsAttention {
|
||||||
|
height: .6em;
|
||||||
|
border-right: 0;
|
||||||
|
}
|
||||||
|
&.ok {
|
||||||
|
height: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bad > .bar.active {
|
||||||
|
background-color: #c00;
|
||||||
|
}
|
||||||
|
&.ok > .bar.active {
|
||||||
|
background-color: #080;
|
||||||
|
}
|
||||||
|
&.needsAttention > .bar.active {
|
||||||
|
background-color: #dc0;
|
||||||
|
}
|
||||||
|
}
|
70
js/src/ui/StatusIndicator/statusIndicator.js
Normal file
70
js/src/ui/StatusIndicator/statusIndicator.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// 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 React, { Component, PropTypes } from 'react';
|
||||||
|
import ReactTooltip from 'react-tooltip';
|
||||||
|
|
||||||
|
import styles from './statusIndicator.css';
|
||||||
|
|
||||||
|
const statuses = ['bad', 'needsAttention', 'ok'];
|
||||||
|
|
||||||
|
export default class StatusIndicator extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
type: PropTypes.oneOf(['radial', 'signal']),
|
||||||
|
id: PropTypes.string.isRequired,
|
||||||
|
status: PropTypes.oneOf(statuses).isRequired,
|
||||||
|
title: PropTypes.arrayOf(PropTypes.node),
|
||||||
|
tooltipPlacement: PropTypes.oneOf(['left', 'top', 'bottom', 'right'])
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
type: 'signal',
|
||||||
|
title: []
|
||||||
|
};
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { id, status, title, type, tooltipPlacement } = this.props;
|
||||||
|
const tooltip = title.find(x => !x.isEmpty) ? (
|
||||||
|
<ReactTooltip id={ `status-${id}` }>
|
||||||
|
{ title.map(x => (<div key={ x }>{ x }</div>)) }
|
||||||
|
</ReactTooltip>
|
||||||
|
) : null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className={ styles.status }>
|
||||||
|
<span className={ `${styles[type]} ${styles[status]}` }
|
||||||
|
data-tip={ title.length }
|
||||||
|
data-for={ `status-${id}` }
|
||||||
|
data-place={ tooltipPlacement }
|
||||||
|
data-effect='solid'
|
||||||
|
>
|
||||||
|
{ type === 'signal' && statuses.map(this.renderBar) }
|
||||||
|
</span>
|
||||||
|
{tooltip}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderBar = (signal) => {
|
||||||
|
const idx = statuses.indexOf(this.props.status);
|
||||||
|
const isActive = statuses.indexOf(signal) <= idx;
|
||||||
|
const activeClass = isActive ? styles.active : '';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span key={ signal } className={ `${styles.bar} ${styles[signal]} ${activeClass}` } />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -52,6 +52,7 @@ export SectionList from './SectionList';
|
|||||||
export SelectionList from './SelectionList';
|
export SelectionList from './SelectionList';
|
||||||
export ShortenedHash from './ShortenedHash';
|
export ShortenedHash from './ShortenedHash';
|
||||||
export SignerIcon from './SignerIcon';
|
export SignerIcon from './SignerIcon';
|
||||||
|
export StatusIndicator from './StatusIndicator';
|
||||||
export Tags from './Tags';
|
export Tags from './Tags';
|
||||||
export Title from './Title';
|
export Title from './Title';
|
||||||
export Tooltips, { Tooltip } from './Tooltips';
|
export Tooltips, { Tooltip } from './Tooltips';
|
||||||
|
@ -43,6 +43,7 @@ class Accounts extends Component {
|
|||||||
accountsInfo: PropTypes.object.isRequired,
|
accountsInfo: PropTypes.object.isRequired,
|
||||||
availability: PropTypes.string.isRequired,
|
availability: PropTypes.string.isRequired,
|
||||||
hasAccounts: PropTypes.bool.isRequired,
|
hasAccounts: PropTypes.bool.isRequired,
|
||||||
|
health: PropTypes.object.isRequired,
|
||||||
setVisibleAccounts: PropTypes.func.isRequired
|
setVisibleAccounts: PropTypes.func.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -496,12 +497,14 @@ class Accounts extends Component {
|
|||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
const { accounts, accountsInfo, hasAccounts } = state.personal;
|
const { accounts, accountsInfo, hasAccounts } = state.personal;
|
||||||
const { availability = 'unknown' } = state.nodeStatus.nodeKind || {};
|
const { availability = 'unknown' } = state.nodeStatus.nodeKind || {};
|
||||||
|
const { health } = state.nodeStatus;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
accounts,
|
accounts,
|
||||||
accountsInfo,
|
accountsInfo,
|
||||||
availability,
|
availability,
|
||||||
hasAccounts
|
hasAccounts,
|
||||||
|
health
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ import React, { Component, PropTypes } from 'react';
|
|||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { BlockStatus } from '~/ui';
|
import { BlockStatus, StatusIndicator } from '~/ui';
|
||||||
|
|
||||||
import styles from './status.css';
|
import styles from './status.css';
|
||||||
|
|
||||||
@ -28,11 +28,12 @@ class Status extends Component {
|
|||||||
isTest: PropTypes.bool,
|
isTest: PropTypes.bool,
|
||||||
netChain: PropTypes.string,
|
netChain: PropTypes.string,
|
||||||
netPeers: PropTypes.object,
|
netPeers: PropTypes.object,
|
||||||
|
health: PropTypes.object,
|
||||||
upgradeStore: PropTypes.object.isRequired
|
upgradeStore: PropTypes.object.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { clientVersion, isTest, netChain, netPeers } = this.props;
|
const { clientVersion, isTest, netChain, netPeers, health } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.status }>
|
<div className={ styles.status }>
|
||||||
@ -44,13 +45,20 @@ class Status extends Component {
|
|||||||
{ this.renderUpgradeButton() }
|
{ this.renderUpgradeButton() }
|
||||||
</div>
|
</div>
|
||||||
<div className={ styles.netinfo }>
|
<div className={ styles.netinfo }>
|
||||||
|
<div>
|
||||||
|
<StatusIndicator
|
||||||
|
type='signal'
|
||||||
|
id='application.status.health'
|
||||||
|
status={ health.overall.status }
|
||||||
|
title={ health.overall.message }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span title={ `${netPeers.connected.toFormat()}/${netPeers.max.toFormat()} peers` }>
|
||||||
<BlockStatus />
|
<BlockStatus />
|
||||||
|
</span>
|
||||||
<div className={ `${styles.network} ${styles[isTest ? 'test' : 'live']}` }>
|
<div className={ `${styles.network} ${styles[isTest ? 'test' : 'live']}` }>
|
||||||
{ netChain }
|
{ netChain }
|
||||||
</div>
|
</div>
|
||||||
<div className={ styles.peers }>
|
|
||||||
{ netPeers.connected.toFormat() }/{ netPeers.max.toFormat() } peers
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -102,14 +110,7 @@ class Status extends Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return;
|
||||||
<div>
|
|
||||||
<FormattedMessage
|
|
||||||
id='application.status.consensus.unknown'
|
|
||||||
defaultMessage='Upgrade status is unknown.'
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderUpgradeButton () {
|
renderUpgradeButton () {
|
||||||
@ -136,10 +137,11 @@ class Status extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
const { clientVersion, netPeers, netChain, isTest } = state.nodeStatus;
|
const { clientVersion, health, netPeers, netChain, isTest } = state.nodeStatus;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
clientVersion,
|
clientVersion,
|
||||||
|
health,
|
||||||
netPeers,
|
netPeers,
|
||||||
netChain,
|
netChain,
|
||||||
isTest
|
isTest
|
||||||
|
@ -81,6 +81,16 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.indicatorTab {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
flex: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indicator {
|
||||||
|
padding: 20px 12px 0;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
.first {
|
.first {
|
||||||
margin-left: -24px;
|
margin-left: -24px;
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ import { Link } from 'react-router';
|
|||||||
import { Toolbar, ToolbarGroup } from 'material-ui/Toolbar';
|
import { Toolbar, ToolbarGroup } from 'material-ui/Toolbar';
|
||||||
import { isEqual } from 'lodash';
|
import { isEqual } from 'lodash';
|
||||||
|
|
||||||
import { Tooltip } from '~/ui';
|
import { Tooltip, StatusIndicator } from '~/ui';
|
||||||
|
|
||||||
import Tab from './Tab';
|
import Tab from './Tab';
|
||||||
import styles from './tabBar.css';
|
import styles from './tabBar.css';
|
||||||
@ -33,6 +33,7 @@ class TabBar extends Component {
|
|||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
pending: PropTypes.array,
|
pending: PropTypes.array,
|
||||||
|
health: PropTypes.object.isRequired,
|
||||||
views: PropTypes.array.isRequired
|
views: PropTypes.array.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -41,12 +42,29 @@ class TabBar extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
|
const { health } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Toolbar className={ styles.toolbar }>
|
<Toolbar className={ styles.toolbar }>
|
||||||
<ToolbarGroup className={ styles.first }>
|
<ToolbarGroup className={ styles.first }>
|
||||||
<div />
|
<div />
|
||||||
</ToolbarGroup>
|
</ToolbarGroup>
|
||||||
<div className={ styles.tabs }>
|
<div className={ styles.tabs }>
|
||||||
|
<Link
|
||||||
|
activeClassName={ styles.tabactive }
|
||||||
|
className={ `${styles.tabLink} ${styles.indicatorTab}` }
|
||||||
|
key='status'
|
||||||
|
to='/status'
|
||||||
|
>
|
||||||
|
<div className={ styles.indicator }>
|
||||||
|
<StatusIndicator
|
||||||
|
type='signal'
|
||||||
|
id='topbar.health'
|
||||||
|
status={ health.overall.status }
|
||||||
|
title={ health.overall.message }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
{ this.renderTabItems() }
|
{ this.renderTabItems() }
|
||||||
<Tooltip
|
<Tooltip
|
||||||
className={ styles.tabbarTooltip }
|
className={ styles.tabbarTooltip }
|
||||||
@ -101,6 +119,7 @@ function mapStateToProps (initState) {
|
|||||||
return (state) => {
|
return (state) => {
|
||||||
const { availability = 'unknown' } = state.nodeStatus.nodeKind || {};
|
const { availability = 'unknown' } = state.nodeStatus.nodeKind || {};
|
||||||
const { views } = state.settings;
|
const { views } = state.settings;
|
||||||
|
const { health } = state.nodeStatus;
|
||||||
|
|
||||||
const viewIds = Object
|
const viewIds = Object
|
||||||
.keys(views)
|
.keys(views)
|
||||||
@ -114,7 +133,7 @@ function mapStateToProps (initState) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (isEqual(viewIds, filteredViewIds)) {
|
if (isEqual(viewIds, filteredViewIds)) {
|
||||||
return { views: filteredViews };
|
return { views: filteredViews, health };
|
||||||
}
|
}
|
||||||
|
|
||||||
filteredViewIds = viewIds;
|
filteredViewIds = viewIds;
|
||||||
@ -123,7 +142,7 @@ function mapStateToProps (initState) {
|
|||||||
id
|
id
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return { views: filteredViews };
|
return { views: filteredViews, health };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,12 @@ function createStore () {
|
|||||||
nodeStatus: {
|
nodeStatus: {
|
||||||
nodeKind: {
|
nodeKind: {
|
||||||
'availability': 'personal'
|
'availability': 'personal'
|
||||||
|
},
|
||||||
|
health: {
|
||||||
|
overall: {
|
||||||
|
status: 'ok',
|
||||||
|
message: []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -24,7 +24,7 @@ import { connect } from 'react-redux';
|
|||||||
import store from 'store';
|
import store from 'store';
|
||||||
|
|
||||||
import imagesEthcoreBlock from '~/../assets/images/parity-logo-white-no-text.svg';
|
import imagesEthcoreBlock from '~/../assets/images/parity-logo-white-no-text.svg';
|
||||||
import { AccountCard, Badge, Button, ContainerTitle, IdentityIcon, ParityBackground, SelectionList } from '~/ui';
|
import { AccountCard, Badge, Button, ContainerTitle, IdentityIcon, ParityBackground, SelectionList, StatusIndicator } from '~/ui';
|
||||||
import { CancelIcon, FingerprintIcon } from '~/ui/Icons';
|
import { CancelIcon, FingerprintIcon } from '~/ui/Icons';
|
||||||
import DappsStore from '~/views/Dapps/dappsStore';
|
import DappsStore from '~/views/Dapps/dappsStore';
|
||||||
import { Embedded as Signer } from '~/views/Signer';
|
import { Embedded as Signer } from '~/views/Signer';
|
||||||
@ -50,7 +50,8 @@ class ParityBar extends Component {
|
|||||||
static propTypes = {
|
static propTypes = {
|
||||||
dapp: PropTypes.bool,
|
dapp: PropTypes.bool,
|
||||||
externalLink: PropTypes.string,
|
externalLink: PropTypes.string,
|
||||||
pending: PropTypes.array
|
pending: PropTypes.array,
|
||||||
|
health: PropTypes.object
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
@ -210,7 +211,7 @@ class ParityBar extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderBar () {
|
renderBar () {
|
||||||
const { dapp } = this.props;
|
const { dapp, health } = this.props;
|
||||||
|
|
||||||
if (!dapp) {
|
if (!dapp) {
|
||||||
return null;
|
return null;
|
||||||
@ -218,6 +219,13 @@ class ParityBar extends Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.cornercolor }>
|
<div className={ styles.cornercolor }>
|
||||||
|
<StatusIndicator
|
||||||
|
type='signal'
|
||||||
|
id='paritybar.health'
|
||||||
|
status={ health.overall.status }
|
||||||
|
title={ health.overall.message }
|
||||||
|
tooltipPlacement='right'
|
||||||
|
/>
|
||||||
<Button
|
<Button
|
||||||
className={ styles.iconButton }
|
className={ styles.iconButton }
|
||||||
icon={
|
icon={
|
||||||
@ -699,9 +707,11 @@ class ParityBar extends Component {
|
|||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
const { pending } = state.signer;
|
const { pending } = state.signer;
|
||||||
|
const { health } = state.nodeStatus;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pending
|
pending,
|
||||||
|
health
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,14 @@ function createRedux (state = {}) {
|
|||||||
},
|
},
|
||||||
signer: {
|
signer: {
|
||||||
pending: []
|
pending: []
|
||||||
|
},
|
||||||
|
nodeStatus: {
|
||||||
|
health: {
|
||||||
|
overall: {
|
||||||
|
status: 'ok',
|
||||||
|
message: []
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, state)
|
}, state)
|
||||||
};
|
};
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import imagesEthcoreBlock from '~/../assets/images/parity-logo-white-no-text.svg';
|
import imagesEthcoreBlock from '~/../assets/images/parity-logo-white-no-text.svg';
|
||||||
import { AccountsIcon, AddressesIcon, AppsIcon, ContactsIcon, FingerprintIcon, SettingsIcon, StatusIcon } from '~/ui/Icons';
|
import { AccountsIcon, AddressesIcon, AppsIcon, ContactsIcon, FingerprintIcon, SettingsIcon } from '~/ui/Icons';
|
||||||
|
|
||||||
import styles from './views.css';
|
import styles from './views.css';
|
||||||
|
|
||||||
@ -65,14 +65,6 @@ const defaultViews = {
|
|||||||
value: 'contract'
|
value: 'contract'
|
||||||
},
|
},
|
||||||
|
|
||||||
status: {
|
|
||||||
active: false,
|
|
||||||
onlyPersonal: true,
|
|
||||||
icon: <StatusIcon />,
|
|
||||||
route: '/status',
|
|
||||||
value: 'status'
|
|
||||||
},
|
|
||||||
|
|
||||||
signer: {
|
signer: {
|
||||||
active: true,
|
active: true,
|
||||||
fixed: true,
|
fixed: true,
|
||||||
|
@ -113,17 +113,6 @@ class Views extends Component {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
{
|
|
||||||
this.renderView('status',
|
|
||||||
<FormattedMessage
|
|
||||||
id='settings.views.status.label'
|
|
||||||
/>,
|
|
||||||
<FormattedMessage
|
|
||||||
id='settings.views.status.description'
|
|
||||||
defaultMessage='See how the Parity node is performing in terms of connections to the network, logs from the actual running instance and details of mining (if enabled and configured).'
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
this.renderView('signer',
|
this.renderView('signer',
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
|
152
js/src/views/Status/Health/health.js
Normal file
152
js/src/views/Status/Health/health.js
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
// 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 React, { Component, PropTypes } from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import { Container, ContainerTitle, StatusIndicator } from '~/ui';
|
||||||
|
|
||||||
|
import grid from '../NodeStatus/nodeStatus.css';
|
||||||
|
|
||||||
|
const HealthItem = (props) => {
|
||||||
|
const status = props.item.status || 'needsAttention';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3>
|
||||||
|
<StatusIndicator
|
||||||
|
id={ props.id }
|
||||||
|
title={ [
|
||||||
|
(<div>{ props.item.message }</div>)
|
||||||
|
] }
|
||||||
|
status={ status }
|
||||||
|
/>
|
||||||
|
{ props.title }
|
||||||
|
<small> ({ props.details })</small>
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
{ status !== 'ok' ? props.item.message : '' }
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
HealthItem.propTypes = {
|
||||||
|
id: PropTypes.string.isRequired,
|
||||||
|
title: PropTypes.node.isRequired,
|
||||||
|
details: PropTypes.oneOfType([
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.node
|
||||||
|
]).isRequired,
|
||||||
|
item: PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
class Health extends Component {
|
||||||
|
static contextTypes = {
|
||||||
|
api: PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
peers: PropTypes.object.isRequired,
|
||||||
|
sync: PropTypes.object.isRequired,
|
||||||
|
time: PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
state = {};
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { peers, sync, time } = this.props;
|
||||||
|
const [yes, no] = [(
|
||||||
|
<FormattedMessage
|
||||||
|
id='status.health.yes'
|
||||||
|
defaultMessage='yes'
|
||||||
|
/>
|
||||||
|
), (
|
||||||
|
<FormattedMessage
|
||||||
|
id='status.health.no'
|
||||||
|
defaultMessage='no'
|
||||||
|
/>
|
||||||
|
)];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<ContainerTitle
|
||||||
|
title={
|
||||||
|
<div>
|
||||||
|
<FormattedMessage
|
||||||
|
id='status.health.title'
|
||||||
|
defaultMessage='Node Health'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<div className={ grid.container }>
|
||||||
|
<div className={ grid.row }>
|
||||||
|
<div className={ grid.col4 }>
|
||||||
|
<HealthItem
|
||||||
|
id='status.health.sync'
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id='status.health.sync'
|
||||||
|
defaultMessage='Chain Synchronized'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
details={ !sync.details ? yes : no }
|
||||||
|
item={ sync }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={ grid.col4 }>
|
||||||
|
<HealthItem
|
||||||
|
id='status.health.peers'
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id='status.health.peers'
|
||||||
|
defaultMessage='Connected Peers'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
details={ (peers.details || []).join('/') }
|
||||||
|
item={ peers }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={ grid.col4 }>
|
||||||
|
<HealthItem
|
||||||
|
id='status.health.time'
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id='status.health.time'
|
||||||
|
defaultMessage='Time Synchronized'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
details={ `${time.details || 0} ms` }
|
||||||
|
item={ time }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStateToProps (state) {
|
||||||
|
return state.nodeStatus.health;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
null
|
||||||
|
)(Health);
|
17
js/src/views/Status/Health/index.js
Normal file
17
js/src/views/Status/Health/index.js
Normal 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 './health';
|
@ -44,7 +44,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.col,
|
.col,
|
||||||
.col3, .col4_5, .col6, .col12 {
|
.col3, .col4, .col4_5, .col6, .col12 {
|
||||||
float: left;
|
float: left;
|
||||||
padding: 0 1em;
|
padding: 0 1em;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@ -57,6 +57,13 @@
|
|||||||
width: calc(100% / 12 * 3);
|
width: calc(100% / 12 * 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.col4 {
|
||||||
|
width: 33.3%;
|
||||||
|
width: -webkit-calc(100% / 12 * 4);
|
||||||
|
width: -moz-calc(100% / 12 * 4);
|
||||||
|
width: calc(100% / 12 * 4);
|
||||||
|
}
|
||||||
|
|
||||||
.col4_5 {
|
.col4_5 {
|
||||||
width: 37.5%;
|
width: 37.5%;
|
||||||
width: -webkit-calc(100% / 12 * 4.5);
|
width: -webkit-calc(100% / 12 * 4.5);
|
||||||
|
@ -20,6 +20,7 @@ import { FormattedMessage } from 'react-intl';
|
|||||||
import { Page } from '~/ui';
|
import { Page } from '~/ui';
|
||||||
|
|
||||||
import Debug from './Debug';
|
import Debug from './Debug';
|
||||||
|
import Health from './Health';
|
||||||
import Peers from './Peers';
|
import Peers from './Peers';
|
||||||
import NodeStatus from './NodeStatus';
|
import NodeStatus from './NodeStatus';
|
||||||
|
|
||||||
@ -35,6 +36,7 @@ export default () => (
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className={ styles.body }>
|
<div className={ styles.body }>
|
||||||
|
<Health />
|
||||||
<NodeStatus />
|
<NodeStatus />
|
||||||
<Peers />
|
<Peers />
|
||||||
<Debug />
|
<Debug />
|
||||||
|
@ -58,3 +58,7 @@
|
|||||||
margin: 0.5em 0;
|
margin: 0.5em 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
font-size: 4rem;
|
||||||
|
}
|
||||||
|
@ -20,7 +20,7 @@ import { FormattedMessage } from 'react-intl';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import store from 'store';
|
import store from 'store';
|
||||||
|
|
||||||
import { Button } from '~/ui';
|
import { Button, StatusIndicator } from '~/ui';
|
||||||
|
|
||||||
import styles from './syncWarning.css';
|
import styles from './syncWarning.css';
|
||||||
|
|
||||||
@ -38,7 +38,8 @@ export const showSyncWarning = () => {
|
|||||||
|
|
||||||
class SyncWarning extends Component {
|
class SyncWarning extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
isSyncing: PropTypes.bool
|
isOk: PropTypes.bool.isRequired,
|
||||||
|
health: PropTypes.object.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
@ -47,10 +48,10 @@ class SyncWarning extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { isSyncing } = this.props;
|
const { isOk, health } = this.props;
|
||||||
const { dontShowAgain, show } = this.state;
|
const { dontShowAgain, show } = this.state;
|
||||||
|
|
||||||
if (!isSyncing || isSyncing === null || !show) {
|
if (isOk || !show) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,18 +60,19 @@ class SyncWarning extends Component {
|
|||||||
<div className={ styles.overlay } />
|
<div className={ styles.overlay } />
|
||||||
<div className={ styles.modal }>
|
<div className={ styles.modal }>
|
||||||
<div className={ styles.body }>
|
<div className={ styles.body }>
|
||||||
<FormattedMessage
|
<div className={ styles.status }>
|
||||||
id='syncWarning.message.line1'
|
<StatusIndicator
|
||||||
defaultMessage={ `
|
type='signal'
|
||||||
Your Parity node is still syncing to the chain.
|
id='healthWarning.indicator'
|
||||||
` }
|
status={ health.overall.status }
|
||||||
/>
|
|
||||||
<FormattedMessage
|
|
||||||
id='syncWarning.message.line2'
|
|
||||||
defaultMessage={ `
|
|
||||||
Some of the shown information might be out-of-date.
|
|
||||||
` }
|
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{
|
||||||
|
health.overall.message.map(message => (
|
||||||
|
<p key={ message }>{ message }</p>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
<div className={ styles.button }>
|
<div className={ styles.button }>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
@ -113,14 +115,13 @@ class SyncWarning extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
const { syncing } = state.nodeStatus;
|
const { health } = state.nodeStatus;
|
||||||
// syncing could be an Object, false, or null
|
const isNotAvailableYet = health.overall.isReady;
|
||||||
const isSyncing = syncing
|
const isOk = isNotAvailableYet || health.overall.status === 'ok';
|
||||||
? true
|
|
||||||
: syncing;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isSyncing
|
isOk,
|
||||||
|
health
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,12 @@ function createRedux (syncing = null) {
|
|||||||
getState: () => {
|
getState: () => {
|
||||||
return {
|
return {
|
||||||
nodeStatus: {
|
nodeStatus: {
|
||||||
syncing
|
health: {
|
||||||
|
overall: {
|
||||||
|
status: syncing ? 'needsAttention' : 'ok',
|
||||||
|
message: []
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,19 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
test: /\.md$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'html-loader',
|
||||||
|
options: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: 'markdown-loader',
|
||||||
|
options: {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
test: /\.css$/,
|
test: /\.css$/,
|
||||||
include: [ /src/ ],
|
include: [ /src/ ],
|
||||||
|
@ -89,6 +89,8 @@ pub struct Params {
|
|||||||
pub nonce_cap_increment: Option<Uint>,
|
pub nonce_cap_increment: Option<Uint>,
|
||||||
/// See `CommonParams` docs.
|
/// See `CommonParams` docs.
|
||||||
pub remove_dust_contracts : Option<bool>,
|
pub remove_dust_contracts : Option<bool>,
|
||||||
|
/// Wasm support flag
|
||||||
|
pub wasm: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -67,10 +67,11 @@ pub fn setup_log(config: &Config) -> Result<Arc<RotatingLogger>, String> {
|
|||||||
|
|
||||||
let mut levels = String::new();
|
let mut levels = String::new();
|
||||||
let mut builder = LogBuilder::new();
|
let mut builder = LogBuilder::new();
|
||||||
// Disable ws info logging by default.
|
// Disable info logging by default for some modules:
|
||||||
builder.filter(Some("ws"), LogLevelFilter::Warn);
|
builder.filter(Some("ws"), LogLevelFilter::Warn);
|
||||||
// Disable rustls info logging by default.
|
builder.filter(Some("reqwest"), LogLevelFilter::Warn);
|
||||||
builder.filter(Some("rustls"), LogLevelFilter::Warn);
|
builder.filter(Some("rustls"), LogLevelFilter::Warn);
|
||||||
|
// Enable info for others.
|
||||||
builder.filter(None, LogLevelFilter::Info);
|
builder.filter(None, LogLevelFilter::Info);
|
||||||
|
|
||||||
if let Ok(lvl) = env::var("RUST_LOG") {
|
if let Ok(lvl) = env::var("RUST_LOG") {
|
||||||
|
@ -71,7 +71,7 @@ pub fn execute(cmd: AccountCmd) -> Result<String, String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn keys_dir(path: String, spec: SpecType) -> Result<RootDiskDirectory, String> {
|
fn keys_dir(path: String, spec: SpecType) -> Result<RootDiskDirectory, String> {
|
||||||
let spec = spec.spec()?;
|
let spec = spec.spec(&::std::env::temp_dir())?;
|
||||||
let mut path = PathBuf::from(&path);
|
let mut path = PathBuf::from(&path);
|
||||||
path.push(spec.data_dir);
|
path.push(spec.data_dir);
|
||||||
RootDiskDirectory::create(path).map_err(|e| format!("Could not open keys directory: {}", e))
|
RootDiskDirectory::create(path).map_err(|e| format!("Could not open keys directory: {}", e))
|
||||||
|
@ -29,7 +29,7 @@ use ethcore::error::ImportError;
|
|||||||
use ethcore::miner::Miner;
|
use ethcore::miner::Miner;
|
||||||
use ethcore::verification::queue::VerifierSettings;
|
use ethcore::verification::queue::VerifierSettings;
|
||||||
use cache::CacheConfig;
|
use cache::CacheConfig;
|
||||||
use informant::{Informant, MillisecondDuration};
|
use informant::{Informant, FullNodeInformantData, MillisecondDuration};
|
||||||
use params::{SpecType, Pruning, Switch, tracing_switch_to_bool, fatdb_switch_to_bool};
|
use params::{SpecType, Pruning, Switch, tracing_switch_to_bool, fatdb_switch_to_bool};
|
||||||
use helpers::{to_client_config, execute_upgrades};
|
use helpers::{to_client_config, execute_upgrades};
|
||||||
use dir::Directories;
|
use dir::Directories;
|
||||||
@ -148,7 +148,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> {
|
|||||||
let timer = Instant::now();
|
let timer = Instant::now();
|
||||||
|
|
||||||
// load spec file
|
// load spec file
|
||||||
let spec = cmd.spec.spec()?;
|
let spec = cmd.spec.spec(&cmd.dirs.cache)?;
|
||||||
|
|
||||||
// load genesis hash
|
// load genesis hash
|
||||||
let genesis_hash = spec.genesis_header().hash();
|
let genesis_hash = spec.genesis_header().hash();
|
||||||
@ -238,7 +238,17 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let informant = Arc::new(Informant::new(client.clone(), None, None, None, None, cmd.with_color));
|
let informant = Arc::new(Informant::new(
|
||||||
|
FullNodeInformantData {
|
||||||
|
client: client.clone(),
|
||||||
|
sync: None,
|
||||||
|
net: None,
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
cmd.with_color,
|
||||||
|
));
|
||||||
|
|
||||||
service.register_io_handler(informant).map_err(|_| "Unable to register informant handler".to_owned())?;
|
service.register_io_handler(informant).map_err(|_| "Unable to register informant handler".to_owned())?;
|
||||||
|
|
||||||
let do_import = |bytes| {
|
let do_import = |bytes| {
|
||||||
@ -320,7 +330,7 @@ fn start_client(
|
|||||||
) -> Result<ClientService, String> {
|
) -> Result<ClientService, String> {
|
||||||
|
|
||||||
// load spec file
|
// load spec file
|
||||||
let spec = spec.spec()?;
|
let spec = spec.spec(&dirs.cache)?;
|
||||||
|
|
||||||
// load genesis hash
|
// load genesis hash
|
||||||
let genesis_hash = spec.genesis_header().hash();
|
let genesis_hash = spec.genesis_header().hash();
|
||||||
@ -517,7 +527,7 @@ fn execute_export_state(cmd: ExportState) -> Result<(), String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn kill_db(cmd: KillBlockchain) -> Result<(), String> {
|
pub fn kill_db(cmd: KillBlockchain) -> Result<(), String> {
|
||||||
let spec = cmd.spec.spec()?;
|
let spec = cmd.spec.spec(&cmd.dirs.cache)?;
|
||||||
let genesis_hash = spec.genesis_header().hash();
|
let genesis_hash = spec.genesis_header().hash();
|
||||||
let db_dirs = cmd.dirs.database(genesis_hash, None, spec.data_dir);
|
let db_dirs = cmd.dirs.database(genesis_hash, None, spec.data_dir);
|
||||||
let user_defaults_path = db_dirs.user_defaults_path();
|
let user_defaults_path = db_dirs.user_defaults_path();
|
||||||
|
@ -78,6 +78,7 @@ disable_periodic = true
|
|||||||
jit = false
|
jit = false
|
||||||
|
|
||||||
[misc]
|
[misc]
|
||||||
|
ntp_server = "pool.ntp.org:123"
|
||||||
logging = "own_tx=trace"
|
logging = "own_tx=trace"
|
||||||
log_file = "/var/log/parity.log"
|
log_file = "/var/log/parity.log"
|
||||||
color = true
|
color = true
|
||||||
|
@ -180,8 +180,10 @@ usage! {
|
|||||||
or |c: &Config| otry!(c.rpc).apis.as_ref().map(|vec| vec.join(",")),
|
or |c: &Config| otry!(c.rpc).apis.as_ref().map(|vec| vec.join(",")),
|
||||||
flag_jsonrpc_hosts: String = "none",
|
flag_jsonrpc_hosts: String = "none",
|
||||||
or |c: &Config| otry!(c.rpc).hosts.as_ref().map(|vec| vec.join(",")),
|
or |c: &Config| otry!(c.rpc).hosts.as_ref().map(|vec| vec.join(",")),
|
||||||
flag_jsonrpc_threads: Option<usize> = None,
|
flag_jsonrpc_server_threads: Option<usize> = None,
|
||||||
or |c: &Config| otry!(c.rpc).threads.map(Some),
|
or |c: &Config| otry!(c.rpc).server_threads.map(Some),
|
||||||
|
flag_jsonrpc_threads: usize = 0usize,
|
||||||
|
or |c: &Config| otry!(c.rpc).processing_threads,
|
||||||
|
|
||||||
// WS
|
// WS
|
||||||
flag_no_ws: bool = false,
|
flag_no_ws: bool = false,
|
||||||
@ -250,6 +252,8 @@ usage! {
|
|||||||
or |c: &Config| otry!(c.mining).force_sealing.clone(),
|
or |c: &Config| otry!(c.mining).force_sealing.clone(),
|
||||||
flag_reseal_on_txs: String = "own",
|
flag_reseal_on_txs: String = "own",
|
||||||
or |c: &Config| otry!(c.mining).reseal_on_txs.clone(),
|
or |c: &Config| otry!(c.mining).reseal_on_txs.clone(),
|
||||||
|
flag_reseal_on_uncle: bool = false,
|
||||||
|
or |c: &Config| otry!(c.mining).reseal_on_uncle.clone(),
|
||||||
flag_reseal_min_period: u64 = 2000u64,
|
flag_reseal_min_period: u64 = 2000u64,
|
||||||
or |c: &Config| otry!(c.mining).reseal_min_period.clone(),
|
or |c: &Config| otry!(c.mining).reseal_min_period.clone(),
|
||||||
flag_reseal_max_period: u64 = 120000u64,
|
flag_reseal_max_period: u64 = 120000u64,
|
||||||
@ -350,6 +354,8 @@ usage! {
|
|||||||
or |c: &Config| otry!(c.vm).jit.clone(),
|
or |c: &Config| otry!(c.vm).jit.clone(),
|
||||||
|
|
||||||
// -- Miscellaneous Options
|
// -- Miscellaneous Options
|
||||||
|
flag_ntp_server: String = "pool.ntp.org:123",
|
||||||
|
or |c: &Config| otry!(c.misc).ntp_server.clone(),
|
||||||
flag_logging: Option<String> = None,
|
flag_logging: Option<String> = None,
|
||||||
or |c: &Config| otry!(c.misc).logging.clone().map(Some),
|
or |c: &Config| otry!(c.misc).logging.clone().map(Some),
|
||||||
flag_log_file: Option<String> = None,
|
flag_log_file: Option<String> = None,
|
||||||
@ -466,7 +472,8 @@ struct Rpc {
|
|||||||
cors: Option<String>,
|
cors: Option<String>,
|
||||||
apis: Option<Vec<String>>,
|
apis: Option<Vec<String>>,
|
||||||
hosts: Option<Vec<String>>,
|
hosts: Option<Vec<String>>,
|
||||||
threads: Option<usize>,
|
server_threads: Option<usize>,
|
||||||
|
processing_threads: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, PartialEq, Deserialize)]
|
#[derive(Default, Debug, PartialEq, Deserialize)]
|
||||||
@ -524,6 +531,7 @@ struct Mining {
|
|||||||
author: Option<String>,
|
author: Option<String>,
|
||||||
engine_signer: Option<String>,
|
engine_signer: Option<String>,
|
||||||
force_sealing: Option<bool>,
|
force_sealing: Option<bool>,
|
||||||
|
reseal_on_uncle: Option<bool>,
|
||||||
reseal_on_txs: Option<String>,
|
reseal_on_txs: Option<String>,
|
||||||
reseal_min_period: Option<u64>,
|
reseal_min_period: Option<u64>,
|
||||||
reseal_max_period: Option<u64>,
|
reseal_max_period: Option<u64>,
|
||||||
@ -584,6 +592,7 @@ struct VM {
|
|||||||
|
|
||||||
#[derive(Default, Debug, PartialEq, Deserialize)]
|
#[derive(Default, Debug, PartialEq, Deserialize)]
|
||||||
struct Misc {
|
struct Misc {
|
||||||
|
ntp_server: Option<String>,
|
||||||
logging: Option<String>,
|
logging: Option<String>,
|
||||||
log_file: Option<String>,
|
log_file: Option<String>,
|
||||||
color: Option<bool>,
|
color: Option<bool>,
|
||||||
@ -746,7 +755,8 @@ mod tests {
|
|||||||
flag_jsonrpc_cors: Some("null".into()),
|
flag_jsonrpc_cors: Some("null".into()),
|
||||||
flag_jsonrpc_apis: "web3,eth,net,parity,traces,rpc,secretstore".into(),
|
flag_jsonrpc_apis: "web3,eth,net,parity,traces,rpc,secretstore".into(),
|
||||||
flag_jsonrpc_hosts: "none".into(),
|
flag_jsonrpc_hosts: "none".into(),
|
||||||
flag_jsonrpc_threads: None,
|
flag_jsonrpc_server_threads: None,
|
||||||
|
flag_jsonrpc_threads: 0,
|
||||||
|
|
||||||
// WS
|
// WS
|
||||||
flag_no_ws: false,
|
flag_no_ws: false,
|
||||||
@ -788,6 +798,7 @@ mod tests {
|
|||||||
flag_reseal_on_txs: "all".into(),
|
flag_reseal_on_txs: "all".into(),
|
||||||
flag_reseal_min_period: 4000u64,
|
flag_reseal_min_period: 4000u64,
|
||||||
flag_reseal_max_period: 60000u64,
|
flag_reseal_max_period: 60000u64,
|
||||||
|
flag_reseal_on_uncle: false,
|
||||||
flag_work_queue_size: 20usize,
|
flag_work_queue_size: 20usize,
|
||||||
flag_tx_gas_limit: Some("6283184".into()),
|
flag_tx_gas_limit: Some("6283184".into()),
|
||||||
flag_tx_time_limit: Some(100u64),
|
flag_tx_time_limit: Some(100u64),
|
||||||
@ -882,6 +893,7 @@ mod tests {
|
|||||||
flag_dapps_apis_all: None,
|
flag_dapps_apis_all: None,
|
||||||
|
|
||||||
// -- Miscellaneous Options
|
// -- Miscellaneous Options
|
||||||
|
flag_ntp_server: "pool.ntp.org:123".into(),
|
||||||
flag_version: false,
|
flag_version: false,
|
||||||
flag_logging: Some("own_tx=trace".into()),
|
flag_logging: Some("own_tx=trace".into()),
|
||||||
flag_log_file: Some("/var/log/parity.log".into()),
|
flag_log_file: Some("/var/log/parity.log".into()),
|
||||||
@ -973,7 +985,8 @@ mod tests {
|
|||||||
cors: None,
|
cors: None,
|
||||||
apis: None,
|
apis: None,
|
||||||
hosts: None,
|
hosts: None,
|
||||||
threads: None,
|
server_threads: None,
|
||||||
|
processing_threads: None,
|
||||||
}),
|
}),
|
||||||
ipc: Some(Ipc {
|
ipc: Some(Ipc {
|
||||||
disable: None,
|
disable: None,
|
||||||
@ -1012,6 +1025,7 @@ mod tests {
|
|||||||
engine_signer: Some("0xdeadbeefcafe0000000000000000000000000001".into()),
|
engine_signer: Some("0xdeadbeefcafe0000000000000000000000000001".into()),
|
||||||
force_sealing: Some(true),
|
force_sealing: Some(true),
|
||||||
reseal_on_txs: Some("all".into()),
|
reseal_on_txs: Some("all".into()),
|
||||||
|
reseal_on_uncle: None,
|
||||||
reseal_min_period: Some(4000),
|
reseal_min_period: Some(4000),
|
||||||
reseal_max_period: Some(60000),
|
reseal_max_period: Some(60000),
|
||||||
work_queue_size: None,
|
work_queue_size: None,
|
||||||
@ -1056,6 +1070,7 @@ mod tests {
|
|||||||
jit: Some(false),
|
jit: Some(false),
|
||||||
}),
|
}),
|
||||||
misc: Some(Misc {
|
misc: Some(Misc {
|
||||||
|
ntp_server: Some("pool.ntp.org:123".into()),
|
||||||
logging: Some("own_tx=trace".into()),
|
logging: Some("own_tx=trace".into()),
|
||||||
log_file: Some("/var/log/parity.log".into()),
|
log_file: Some("/var/log/parity.log".into()),
|
||||||
color: Some(true),
|
color: Some(true),
|
||||||
|
@ -176,9 +176,12 @@ API and Console Options:
|
|||||||
is additional security against some attack
|
is additional security against some attack
|
||||||
vectors. Special options: "all", "none",
|
vectors. Special options: "all", "none",
|
||||||
(default: {flag_jsonrpc_hosts}).
|
(default: {flag_jsonrpc_hosts}).
|
||||||
--jsonrpc-threads THREADS Enables experimental faster implementation of JSON-RPC server.
|
--jsonrpc-server-threads NUM Enables experimental faster implementation of JSON-RPC server.
|
||||||
Requires Dapps server to be disabled
|
Requires Dapps server to be disabled
|
||||||
using --no-dapps. (default: {flag_jsonrpc_threads:?})
|
using --no-dapps. (default: {flag_jsonrpc_server_threads:?})
|
||||||
|
--jsonrpc-threads THREADS Turn on additional processing threads in all RPC servers.
|
||||||
|
Setting this to non-zero value allows parallel cpu-heavy queries
|
||||||
|
execution. (default: {flag_jsonrpc_threads})
|
||||||
|
|
||||||
--no-ws Disable the WebSockets server. (default: {flag_no_ws})
|
--no-ws Disable the WebSockets server. (default: {flag_no_ws})
|
||||||
--ws-port PORT Specify the port portion of the WebSockets server
|
--ws-port PORT Specify the port portion of the WebSockets server
|
||||||
@ -262,6 +265,9 @@ Sealing/Mining Options:
|
|||||||
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-on-uncle Force the node to author new blocks when a new uncle
|
||||||
|
block is imported.
|
||||||
|
(default: {flag_reseal_on_uncle})
|
||||||
--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}).
|
||||||
@ -461,6 +467,8 @@ 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:
|
||||||
|
--ntp-server HOST NTP server to provide current time (host:port). Used to verify node health.
|
||||||
|
(default: {flag_ntp_server})
|
||||||
-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
|
||||||
|
@ -34,7 +34,7 @@ use rpc::{IpcConfiguration, HttpConfiguration, WsConfiguration, UiConfiguration}
|
|||||||
use rpc_apis::ApiSet;
|
use rpc_apis::ApiSet;
|
||||||
use parity_rpc::NetworkSettings;
|
use parity_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_and_local,
|
||||||
geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address, to_gas_limit, to_queue_strategy};
|
geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address, to_gas_limit, to_queue_strategy};
|
||||||
use params::{SpecType, ResealPolicy, AccountsConfig, GasPricerConfig, MinerExtras, Pruning, Switch};
|
use params::{SpecType, ResealPolicy, AccountsConfig, GasPricerConfig, MinerExtras, Pruning, Switch};
|
||||||
use ethcore_logger::Config as LogConfig;
|
use ethcore_logger::Config as LogConfig;
|
||||||
@ -137,7 +137,7 @@ impl Configuration {
|
|||||||
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_server_threads.is_some() && dapps_conf.enabled {
|
||||||
dapps_conf.enabled = false;
|
dapps_conf.enabled = false;
|
||||||
writeln!(&mut stderr(), "Warning: Disabling Dapps server because fast RPC server was enabled.").expect("Error writing to stderr.")
|
writeln!(&mut stderr(), "Warning: Disabling Dapps server because fast RPC server was enabled.").expect("Error writing to stderr.")
|
||||||
}
|
}
|
||||||
@ -526,6 +526,7 @@ impl Configuration {
|
|||||||
force_sealing: self.args.flag_force_sealing,
|
force_sealing: self.args.flag_force_sealing,
|
||||||
reseal_on_external_tx: reseal.external,
|
reseal_on_external_tx: reseal.external,
|
||||||
reseal_on_own_tx: reseal.own,
|
reseal_on_own_tx: reseal.own,
|
||||||
|
reseal_on_uncle: self.args.flag_reseal_on_uncle,
|
||||||
tx_gas_limit: match self.args.flag_tx_gas_limit {
|
tx_gas_limit: match self.args.flag_tx_gas_limit {
|
||||||
Some(ref d) => to_u256(d)?,
|
Some(ref d) => to_u256(d)?,
|
||||||
None => U256::max_value(),
|
None => U256::max_value(),
|
||||||
@ -555,6 +556,7 @@ impl Configuration {
|
|||||||
fn ui_config(&self) -> UiConfiguration {
|
fn ui_config(&self) -> UiConfiguration {
|
||||||
UiConfiguration {
|
UiConfiguration {
|
||||||
enabled: self.ui_enabled(),
|
enabled: self.ui_enabled(),
|
||||||
|
ntp_server: self.args.flag_ntp_server.clone(),
|
||||||
interface: self.ui_interface(),
|
interface: self.ui_interface(),
|
||||||
port: self.args.flag_ports_shift + self.args.flag_ui_port,
|
port: self.args.flag_ports_shift + self.args.flag_ui_port,
|
||||||
hosts: self.ui_hosts(),
|
hosts: self.ui_hosts(),
|
||||||
@ -564,12 +566,18 @@ impl Configuration {
|
|||||||
fn dapps_config(&self) -> DappsConfiguration {
|
fn dapps_config(&self) -> DappsConfiguration {
|
||||||
DappsConfiguration {
|
DappsConfiguration {
|
||||||
enabled: self.dapps_enabled(),
|
enabled: self.dapps_enabled(),
|
||||||
|
ntp_server: self.args.flag_ntp_server.clone(),
|
||||||
dapps_path: PathBuf::from(self.directories().dapps),
|
dapps_path: PathBuf::from(self.directories().dapps),
|
||||||
extra_dapps: if self.args.cmd_dapp {
|
extra_dapps: if self.args.cmd_dapp {
|
||||||
self.args.arg_path.iter().map(|path| PathBuf::from(path)).collect()
|
self.args.arg_path.iter().map(|path| PathBuf::from(path)).collect()
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
},
|
},
|
||||||
|
extra_embed_on: if self.args.flag_ui_no_validation {
|
||||||
|
vec![("localhost".to_owned(), 3000)]
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -662,7 +670,7 @@ impl Configuration {
|
|||||||
let mut buffer = String::new();
|
let mut buffer = String::new();
|
||||||
let mut node_file = File::open(path).map_err(|e| format!("Error opening reserved nodes file: {}", e))?;
|
let mut node_file = File::open(path).map_err(|e| format!("Error opening reserved nodes file: {}", e))?;
|
||||||
node_file.read_to_string(&mut buffer).map_err(|_| "Error reading reserved node file")?;
|
node_file.read_to_string(&mut buffer).map_err(|_| "Error reading reserved node file")?;
|
||||||
let lines = buffer.lines().map(|s| s.trim().to_owned()).filter(|s| !s.is_empty()).collect::<Vec<_>>();
|
let lines = buffer.lines().map(|s| s.trim().to_owned()).filter(|s| !s.is_empty() && !s.starts_with("#")).collect::<Vec<_>>();
|
||||||
if let Some(invalid) = lines.iter().find(|s| !is_valid_node_url(s)) {
|
if let Some(invalid) = lines.iter().find(|s| !is_valid_node_url(s)) {
|
||||||
return Err(format!("Invalid node address format given for a boot node: {}", invalid));
|
return Err(format!("Invalid node address format given for a boot node: {}", invalid));
|
||||||
}
|
}
|
||||||
@ -824,11 +832,12 @@ impl Configuration {
|
|||||||
},
|
},
|
||||||
hosts: self.rpc_hosts(),
|
hosts: self.rpc_hosts(),
|
||||||
cors: self.rpc_cors(),
|
cors: self.rpc_cors(),
|
||||||
threads: match self.args.flag_jsonrpc_threads {
|
server_threads: match self.args.flag_jsonrpc_server_threads {
|
||||||
Some(threads) if threads > 0 => Some(threads),
|
Some(threads) if threads > 0 => Some(threads),
|
||||||
None => None,
|
None => None,
|
||||||
_ => return Err("--jsonrpc-threads number needs to be positive.".into()),
|
_ => return Err("--jsonrpc-server-threads number needs to be positive.".into()),
|
||||||
}
|
},
|
||||||
|
processing_threads: self.args.flag_jsonrpc_threads,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(conf)
|
Ok(conf)
|
||||||
@ -893,14 +902,20 @@ impl Configuration {
|
|||||||
let local_path = default_local_path();
|
let local_path = default_local_path();
|
||||||
let base_path = self.args.flag_base_path.as_ref().or_else(|| self.args.flag_datadir.as_ref()).map_or_else(|| default_data_path(), |s| s.clone());
|
let base_path = self.args.flag_base_path.as_ref().or_else(|| self.args.flag_datadir.as_ref()).map_or_else(|| default_data_path(), |s| s.clone());
|
||||||
let data_path = replace_home("", &base_path);
|
let data_path = replace_home("", &base_path);
|
||||||
let base_db_path = if self.args.flag_base_path.is_some() && self.args.flag_db_path.is_none() {
|
let is_using_base_path = self.args.flag_base_path.is_some();
|
||||||
// If base_path is set and db_path is not we default to base path subdir instead of LOCAL.
|
// If base_path is set and db_path is not we default to base path subdir instead of LOCAL.
|
||||||
|
let base_db_path = if is_using_base_path && self.args.flag_db_path.is_none() {
|
||||||
"$BASE/chains"
|
"$BASE/chains"
|
||||||
} else {
|
} else {
|
||||||
self.args.flag_db_path.as_ref().map_or(dir::CHAINS_PATH, |s| &s)
|
self.args.flag_db_path.as_ref().map_or(dir::CHAINS_PATH, |s| &s)
|
||||||
};
|
};
|
||||||
|
let cache_path = if is_using_base_path {
|
||||||
|
"$BASE/cache".into()
|
||||||
|
} else {
|
||||||
|
replace_home_and_local(&data_path, &local_path, &dir::CACHE_PATH)
|
||||||
|
};
|
||||||
|
|
||||||
let db_path = replace_home_for_db(&data_path, &local_path, &base_db_path);
|
let db_path = replace_home_and_local(&data_path, &local_path, &base_db_path);
|
||||||
let keys_path = replace_home(&data_path, &self.args.flag_keys_path);
|
let keys_path = replace_home(&data_path, &self.args.flag_keys_path);
|
||||||
let dapps_path = replace_home(&data_path, &self.args.flag_dapps_path);
|
let dapps_path = replace_home(&data_path, &self.args.flag_dapps_path);
|
||||||
let secretstore_path = replace_home(&data_path, &self.args.flag_secretstore_path);
|
let secretstore_path = replace_home(&data_path, &self.args.flag_secretstore_path);
|
||||||
@ -924,6 +939,7 @@ impl Configuration {
|
|||||||
Directories {
|
Directories {
|
||||||
keys: keys_path,
|
keys: keys_path,
|
||||||
base: data_path,
|
base: data_path,
|
||||||
|
cache: cache_path,
|
||||||
db: db_path,
|
db: db_path,
|
||||||
dapps: dapps_path,
|
dapps: dapps_path,
|
||||||
signer: ui_path,
|
signer: ui_path,
|
||||||
@ -1256,6 +1272,7 @@ mod tests {
|
|||||||
support_token_api: true
|
support_token_api: true
|
||||||
}, UiConfiguration {
|
}, UiConfiguration {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
ntp_server: "pool.ntp.org:123".into(),
|
||||||
interface: "127.0.0.1".into(),
|
interface: "127.0.0.1".into(),
|
||||||
port: 8180,
|
port: 8180,
|
||||||
hosts: Some(vec![]),
|
hosts: Some(vec![]),
|
||||||
@ -1496,6 +1513,7 @@ mod tests {
|
|||||||
assert_eq!(conf0.directories().signer, "signer".to_owned());
|
assert_eq!(conf0.directories().signer, "signer".to_owned());
|
||||||
assert_eq!(conf0.ui_config(), UiConfiguration {
|
assert_eq!(conf0.ui_config(), UiConfiguration {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
ntp_server: "pool.ntp.org:123".into(),
|
||||||
interface: "127.0.0.1".into(),
|
interface: "127.0.0.1".into(),
|
||||||
port: 8180,
|
port: 8180,
|
||||||
hosts: Some(vec![]),
|
hosts: Some(vec![]),
|
||||||
@ -1504,14 +1522,17 @@ mod tests {
|
|||||||
assert_eq!(conf1.directories().signer, "signer".to_owned());
|
assert_eq!(conf1.directories().signer, "signer".to_owned());
|
||||||
assert_eq!(conf1.ui_config(), UiConfiguration {
|
assert_eq!(conf1.ui_config(), UiConfiguration {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
ntp_server: "pool.ntp.org:123".into(),
|
||||||
interface: "127.0.0.1".into(),
|
interface: "127.0.0.1".into(),
|
||||||
port: 8180,
|
port: 8180,
|
||||||
hosts: Some(vec![]),
|
hosts: Some(vec![]),
|
||||||
});
|
});
|
||||||
|
assert_eq!(conf1.dapps_config().extra_embed_on, vec![("localhost".to_owned(), 3000)]);
|
||||||
assert_eq!(conf1.ws_config().unwrap().hosts, None);
|
assert_eq!(conf1.ws_config().unwrap().hosts, None);
|
||||||
assert_eq!(conf2.directories().signer, "signer".to_owned());
|
assert_eq!(conf2.directories().signer, "signer".to_owned());
|
||||||
assert_eq!(conf2.ui_config(), UiConfiguration {
|
assert_eq!(conf2.ui_config(), UiConfiguration {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
ntp_server: "pool.ntp.org:123".into(),
|
||||||
interface: "127.0.0.1".into(),
|
interface: "127.0.0.1".into(),
|
||||||
port: 3123,
|
port: 3123,
|
||||||
hosts: Some(vec![]),
|
hosts: Some(vec![]),
|
||||||
@ -1520,6 +1541,7 @@ mod tests {
|
|||||||
assert_eq!(conf3.directories().signer, "signer".to_owned());
|
assert_eq!(conf3.directories().signer, "signer".to_owned());
|
||||||
assert_eq!(conf3.ui_config(), UiConfiguration {
|
assert_eq!(conf3.ui_config(), UiConfiguration {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
ntp_server: "pool.ntp.org:123".into(),
|
||||||
interface: "test".into(),
|
interface: "test".into(),
|
||||||
port: 8180,
|
port: 8180,
|
||||||
hosts: Some(vec![]),
|
hosts: Some(vec![]),
|
||||||
@ -1554,6 +1576,19 @@ mod tests {
|
|||||||
assert!(conf.init_reserved_nodes().is_ok());
|
assert!(conf.init_reserved_nodes().is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_ignore_comments_in_reserved_peers() {
|
||||||
|
let temp = RandomTempPath::new();
|
||||||
|
create_dir(temp.as_str().to_owned()).unwrap();
|
||||||
|
let filename = temp.as_str().to_owned() + "/peers_comments";
|
||||||
|
File::create(filename.clone()).unwrap().write_all(b"# Sample comment\nenode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@172.0.0.1:30303\n").unwrap();
|
||||||
|
let args = vec!["parity", "--reserved-peers", &filename];
|
||||||
|
let conf = Configuration::parse(&args, None).unwrap();
|
||||||
|
let reserved_nodes = conf.init_reserved_nodes();
|
||||||
|
assert!(reserved_nodes.is_ok());
|
||||||
|
assert_eq!(reserved_nodes.unwrap().len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_dev_chain() {
|
fn test_dev_chain() {
|
||||||
let args = vec!["parity", "--chain", "dev"];
|
let args = vec!["parity", "--chain", "dev"];
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user