Merge branch 'master' into csp-fix

This commit is contained in:
Tomasz Drwięga 2017-07-11 13:45:23 +02:00
commit ba4d8ceaf3
No known key found for this signature in database
GPG Key ID: D066F497E62CAF66
118 changed files with 3716 additions and 667 deletions

3
.gitmodules vendored
View File

@ -2,3 +2,6 @@
path = ethcore/res/ethereum/tests
url = https://github.com/ethereum/tests.git
branch = develop
[submodule "ethcore/res/wasm-tests"]
path = ethcore/res/wasm-tests
url = https://github.com/paritytech/wasm-tests

192
Cargo.lock generated
View File

@ -57,6 +57,39 @@ dependencies = [
"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]]
name = "base-x"
version = "0.2.2"
@ -119,6 +152,11 @@ name = "bitflags"
version = "0.7.0"
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]]
name = "bitflags"
version = "0.9.1"
@ -144,6 +182,11 @@ dependencies = [
"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]]
name = "byteorder"
version = "1.0.0"
@ -173,6 +216,21 @@ dependencies = [
"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]]
name = "clippy"
version = "0.0.103"
@ -195,6 +253,14 @@ dependencies = [
"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]]
name = "cookie"
version = "0.3.1"
@ -245,6 +311,11 @@ dependencies = [
"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]]
name = "daemonize"
version = "0.2.2"
@ -253,6 +324,15 @@ dependencies = [
"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]]
name = "deque"
version = "0.3.1"
@ -305,6 +385,14 @@ dependencies = [
"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]]
name = "eth-secp256k1"
version = "0.5.6"
@ -376,6 +464,7 @@ dependencies = [
"native-contracts 0.1.0",
"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)",
"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)",
"rlp 0.2.0",
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
@ -385,6 +474,7 @@ dependencies = [
"stats 0.1.0",
"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)",
"wasm-utils 0.1.0 (git+https://github.com/paritytech/wasm-utils)",
]
[[package]]
@ -1029,7 +1119,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "jsonrpc-core"
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 = [
"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)",
@ -1041,7 +1131,7 @@ dependencies = [
[[package]]
name = "jsonrpc-http-server"
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 = [
"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)",
@ -1054,7 +1144,7 @@ dependencies = [
[[package]]
name = "jsonrpc-ipc-server"
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 = [
"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)",
@ -1067,7 +1157,7 @@ dependencies = [
[[package]]
name = "jsonrpc-macros"
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 = [
"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)",
@ -1077,7 +1167,7 @@ dependencies = [
[[package]]
name = "jsonrpc-minihttp-server"
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 = [
"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)",
@ -1092,7 +1182,7 @@ dependencies = [
[[package]]
name = "jsonrpc-pubsub"
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 = [
"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)",
@ -1102,8 +1192,9 @@ dependencies = [
[[package]]
name = "jsonrpc-server-utils"
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 = [
"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)",
"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)",
@ -1114,7 +1205,7 @@ dependencies = [
[[package]]
name = "jsonrpc-tcp-server"
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 = [
"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)",
@ -1128,11 +1219,13 @@ dependencies = [
[[package]]
name = "jsonrpc-ws-server"
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 = [
"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)",
"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)",
]
@ -1432,6 +1525,19 @@ name = "nom"
version = "1.2.2"
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]]
name = "num"
version = "0.1.32"
@ -1592,6 +1698,7 @@ dependencies = [
"ethsync 1.7.0",
"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-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)",
"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)",
@ -1634,12 +1741,14 @@ dependencies = [
"ethcore-util 1.7.0",
"fetch 0.1.0",
"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-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)",
"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_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-hash-fetch 1.7.0",
"parity-reactor 0.1.0",
@ -1743,6 +1852,7 @@ dependencies = [
"ethsync 1.7.0",
"fetch 0.1.0",
"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-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)",
@ -1848,6 +1958,16 @@ dependencies = [
"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]]
name = "parity-wordlist"
version = "1.0.1"
@ -2193,6 +2313,11 @@ dependencies = [
"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]]
name = "rustc-hex"
version = "1.0.0"
@ -2523,6 +2648,16 @@ dependencies = [
"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]]
name = "termios"
version = "0.2.2"
@ -2743,6 +2878,11 @@ name = "unicode-segmentation"
version = "1.1.0"
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]]
name = "unicode-xid"
version = "0.0.4"
@ -2784,6 +2924,11 @@ name = "utf8-ranges"
version = "1.0.0"
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]]
name = "vecio"
version = "0.1.0"
@ -2807,6 +2952,18 @@ name = "void"
version = "1.0.2"
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]]
name = "winapi"
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 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 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 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"
@ -2891,23 +3051,29 @@ dependencies = [
"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.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 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 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 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 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_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 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 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 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 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 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"
@ -2915,6 +3081,7 @@ dependencies = [
"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 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 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"
@ -2985,6 +3152,7 @@ dependencies = [
"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 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-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"
@ -3003,6 +3171,7 @@ dependencies = [
"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-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 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"
@ -3039,6 +3208,7 @@ dependencies = [
"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 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-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"
@ -3080,6 +3250,7 @@ dependencies = [
"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 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 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"
@ -3103,15 +3274,18 @@ dependencies = [
"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-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 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 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 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 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 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-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>"

View File

@ -25,6 +25,7 @@ serde_json = "1.0"
serde_derive = "1.0"
app_dirs = "1.1.1"
futures = "0.1"
futures-cpupool = "0.1"
fdlimit = "0.1"
ws2_32-sys = "0.2"
ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" }

View File

@ -11,11 +11,13 @@ authors = ["Parity Technologies <admin@parity.io>"]
base32 = "0.3"
env_logger = "0.4"
futures = "0.1"
futures-cpupool = "0.1"
linked-hash-map = "0.3"
log = "0.3"
parity-dapps-glue = "1.7"
mime = "0.2"
mime_guess = "1.6.1"
ntp = "0.2.0"
rand = "0.3"
rustc-hex = "1.0"
serde = "1.0"

View File

@ -18,23 +18,36 @@ use std::sync::Arc;
use hyper::{server, net, Decoder, Encoder, Next, Control};
use hyper::method::Method;
use hyper::status::StatusCode;
use api::types::ApiError;
use api::response;
use api::{response, types};
use api::time::TimeChecker;
use apps::fetcher::Fetcher;
use handlers::extract_url;
use handlers::{self, extract_url};
use endpoint::{Endpoint, Handler, EndpointPath};
use parity_reactor::Remote;
use {SyncStatus};
#[derive(Clone)]
pub struct RestApi {
fetcher: Arc<Fetcher>,
sync_status: Arc<SyncStatus>,
time: TimeChecker,
remote: Remote,
}
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 {
fetcher: fetcher,
fetcher,
sync_status,
time,
remote,
})
}
}
@ -58,11 +71,11 @@ impl RestApiRouter {
path: Some(path),
control: Some(control),
api: api,
handler: response::as_json_error(&ApiError {
handler: Box::new(response::as_json_error(StatusCode::NotFound, &types::ApiError {
code: "404".into(),
title: "Not Found".into(),
detail: "Resource you requested has not been found.".into(),
}),
})),
}
}
@ -75,6 +88,78 @@ impl RestApiRouter {
_ => 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 {
@ -103,6 +188,7 @@ impl server::Handler<net::HttpStream> for RestApiRouter {
let handler = endpoint.and_then(|v| match v {
"ping" => Some(response::ping()),
"health" => Some(self.health(control)),
"content" => self.resolve_content(hash, path, control),
_ => None
});

View File

@ -18,6 +18,8 @@
mod api;
mod response;
mod time;
mod types;
pub use self::api::RestApi;
pub use self::time::TimeChecker;

View File

@ -16,6 +16,8 @@
use serde::Serialize;
use serde_json;
use hyper::status::StatusCode;
use endpoint::Handler;
use handlers::{ContentHandler, EchoHandler};
@ -23,10 +25,16 @@ pub fn empty() -> Box<Handler> {
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)
.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> {

264
dapps/src/api/time.rs Normal file
View 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);
}
}

View File

@ -14,11 +14,54 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
/// A structure representing any error in REST API.
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ApiError {
/// Error code.
pub code: String,
/// Human-readable error summary.
pub title: String,
/// More technical error details.
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>,
}

View File

@ -48,7 +48,7 @@ pub trait Fetcher: Send + Sync + 'static {
}
pub struct ContentFetcher<F: Fetch = FetchClient, R: URLHint + 'static = URLHintContract> {
dapps_path: PathBuf,
cache_path: PathBuf,
resolver: R,
cache: Arc<Mutex<ContentCache>>,
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> {
fn drop(&mut self) {
// 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,
fetch: F,
) -> Self {
let mut dapps_path = env::temp_dir();
dapps_path.push(random_filename());
let mut cache_path = env::temp_dir();
cache_path.push(random_filename());
ContentFetcher {
dapps_path: dapps_path,
cache_path: cache_path,
resolver: resolver,
sync: sync_status,
cache: Arc::new(Mutex::new(ContentCache::default())),
@ -200,7 +200,7 @@ impl<R: URLHint + 'static, F: Fetch> Fetcher for ContentFetcher<F, R> {
control,
installers::Dapp::new(
content_id.clone(),
self.dapps_path.clone(),
self.cache_path.clone(),
Box::new(on_done),
self.embeddable_on.clone(),
),
@ -219,7 +219,7 @@ impl<R: URLHint + 'static, F: Fetch> Fetcher for ContentFetcher<F, R> {
installers::Content::new(
content_id.clone(),
content.mime,
self.dapps_path.clone(),
self.cache_path.clone(),
Box::new(on_done),
),
self.embeddable_on.clone(),
@ -271,6 +271,7 @@ mod tests {
use endpoint::EndpointInfo;
use page::LocalPageEndpoint;
use super::{ContentFetcher, Fetcher};
use {SyncStatus};
#[derive(Clone)]
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]
fn should_true_if_contains_the_app() {
// given
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);
let handler = LocalPageEndpoint::new(path, EndpointInfo {
name: "fake".into(),

View File

@ -26,7 +26,7 @@ use fetch::Fetch;
use parity_dapps::WebApp;
use parity_reactor::Remote;
use parity_ui;
use {WebProxyTokens, ParentFrameSettings, as_embeddable};
use {WebProxyTokens, ParentFrameSettings};
mod app;
mod cache;
@ -52,20 +52,19 @@ pub fn ui() -> Box<Endpoint> {
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> {
Box::new(ui::Redirection::new(as_embeddable(ui_address, dapps_domain)))
pub fn ui_redirection(embeddable: Option<ParentFrameSettings>) -> Box<Endpoint> {
Box::new(ui::Redirection::new(embeddable))
}
pub fn all_endpoints<F: Fetch>(
dapps_path: PathBuf,
extra_dapps: Vec<PathBuf>,
dapps_domain: String,
ui_address: Option<(String, u16)>,
dapps_domain: &str,
embeddable: Option<ParentFrameSettings>,
web_proxy_tokens: Arc<WebProxyTokens>,
remote: Remote,
fetch: F,
) -> Endpoints {
let embeddable = as_embeddable(ui_address.clone(), dapps_domain.clone());
// fetch fs dapps at first to avoid overwriting builtins
let mut pages = fs::local_endpoints(dapps_path, embeddable.clone());
for path in extra_dapps {
@ -78,7 +77,7 @@ pub fn all_endpoints<F: Fetch>(
// NOTE [ToDr] Dapps will be currently embeded on 8180
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()));
Arc::new(pages)

112
dapps/src/handlers/async.rs Normal file
View 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()
}
}
}

View File

@ -40,10 +40,6 @@ impl ContentHandler {
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 {
Self::new_embeddable(code, content, mime!(Text/Html), embeddable_on)
}

View File

@ -16,18 +16,23 @@
//! Hyper handlers implementations.
mod async;
mod content;
mod echo;
mod fetch;
mod redirect;
mod streaming;
pub use self::async::AsyncHandler;
pub use self::content::ContentHandler;
pub use self::echo::EchoHandler;
pub use self::fetch::{ContentFetcherHandler, ContentValidator, FetchControl, ValidatorResponse};
pub use self::redirect::Redirection;
pub use self::streaming::StreamingHandler;
use std::iter;
use util::Itertools;
use url::Url;
use hyper::{server, header, net, uri};
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 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);
format!("frame-ancestors {} {} {} {};",
std,
localhost,
domain,
proxy,
)
ancestors.chain(iter::once(localhost)).join(" ")
} else {
format!("frame-ancestors {} {} {};",
std,
domain,
proxy,
)
}
ancestors.join(" ")
};
format!("frame-ancestors {};", ancestors)
},
None => format!("frame-ancestors 'self';"),
}.into_bytes(),

View File

@ -21,8 +21,10 @@
extern crate base32;
extern crate futures;
extern crate futures_cpupool;
extern crate linked_hash_map;
extern crate mime_guess;
extern crate ntp;
extern crate rand;
extern crate rustc_hex;
extern crate serde;
@ -74,6 +76,7 @@ use std::collections::HashMap;
use jsonrpc_http_server::{self as http, hyper, Origin};
use fetch::Fetch;
use futures_cpupool::CpuPool;
use parity_reactor::Remote;
pub use hash_fetch::urlhint::ContractClient;
@ -82,10 +85,9 @@ pub use hash_fetch::urlhint::ContractClient;
pub trait SyncStatus: Send + Sync {
/// Returns true if there is a major sync happening.
fn is_major_importing(&self) -> bool;
}
impl<F> SyncStatus for F where F: Fn() -> bool + Send + Sync {
fn is_major_importing(&self) -> bool { self() }
/// Returns number of connected and ideal peers.
fn peers(&self) -> (usize, usize);
}
/// Validates Web Proxy tokens
@ -127,21 +129,29 @@ impl Middleware {
}
/// Creates new middleware for UI server.
pub fn ui<F: Fetch + Clone>(
pub fn ui<F: Fetch>(
ntp_server: &str,
pool: CpuPool,
remote: Remote,
dapps_domain: &str,
registrar: Arc<ContractClient>,
sync_status: Arc<SyncStatus>,
fetch: F,
dapps_domain: String,
) -> Self {
let content_fetcher = Arc::new(apps::fetcher::ContentFetcher::new(
hash_fetch::urlhint::URLHintContract::new(registrar),
sync_status,
sync_status.clone(),
remote.clone(),
fetch.clone(),
).embeddable_on(None).allow_dapps(false));
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
};
@ -150,7 +160,7 @@ impl Middleware {
None,
special,
None,
dapps_domain,
dapps_domain.to_owned(),
);
Middleware {
@ -160,39 +170,48 @@ impl Middleware {
}
/// Creates new Dapps server middleware.
pub fn dapps<F: Fetch + Clone>(
pub fn dapps<F: Fetch>(
ntp_server: &str,
pool: CpuPool,
remote: Remote,
ui_address: Option<(String, u16)>,
extra_embed_on: Vec<(String, u16)>,
dapps_path: PathBuf,
extra_dapps: Vec<PathBuf>,
dapps_domain: String,
dapps_domain: &str,
registrar: Arc<ContractClient>,
sync_status: Arc<SyncStatus>,
web_proxy_tokens: Arc<WebProxyTokens>,
fetch: F,
) -> 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(
hash_fetch::urlhint::URLHintContract::new(registrar),
sync_status,
sync_status.clone(),
remote.clone(),
fetch.clone(),
).embeddable_on(embeddable.clone()).allow_dapps(true));
let endpoints = apps::all_endpoints(
dapps_path,
extra_dapps,
dapps_domain.clone(),
ui_address.clone(),
dapps_domain,
embeddable.clone(),
web_proxy_tokens,
remote.clone(),
fetch.clone(),
);
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(
router::SpecialEndpoint::Home,
Some(apps::ui_redirection(ui_address.clone(), dapps_domain.clone())),
Some(apps::ui_redirection(embeddable.clone())),
);
special
};
@ -202,7 +221,7 @@ impl Middleware {
Some(endpoints.clone()),
special,
embeddable,
dapps_domain,
dapps_domain.to_owned(),
);
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();
special.insert(router::SpecialEndpoint::Rpc, None);
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
}
@ -230,8 +260,17 @@ fn address(host: &str, port: u16) -> String {
format!("{}:{}", host, port)
}
fn as_embeddable(ui_address: Option<(String, u16)>, dapps_domain: String) -> Option<ParentFrameSettings> {
ui_address.map(|(host, port)| ParentFrameSettings { host, port, dapps_domain, })
fn as_embeddable(
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
@ -250,6 +289,8 @@ pub struct ParentFrameSettings {
pub host: String,
/// Port
pub port: u16,
/// Additional pages the pages can be embedded on.
pub extra_embed_on: Vec<(String, u16)>,
/// Dapps Domain (web3.site)
pub dapps_domain: String,
}

View File

@ -19,27 +19,24 @@
use endpoint::{Endpoint, Handler, EndpointPath};
use handlers::ContentHandler;
use apps::HOME_PAGE;
use address;
use {address, Embeddable};
pub struct ProxyPac {
signer_address: Option<(String, u16)>,
embeddable: Embeddable,
dapps_domain: String,
}
impl ProxyPac {
pub fn boxed(signer_address: Option<(String, u16)>, dapps_domain: String) -> Box<Endpoint> {
Box::new(ProxyPac {
signer_address: signer_address,
dapps_domain: dapps_domain,
})
pub fn boxed(embeddable: Embeddable, dapps_domain: String) -> Box<Endpoint> {
Box::new(ProxyPac { embeddable, dapps_domain })
}
}
impl Endpoint for ProxyPac {
fn to_handler(&self, path: EndpointPath) -> Box<Handler> {
let signer = self.signer_address
let ui = self.embeddable
.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));
let content = format!(
@ -58,7 +55,7 @@ function FindProxyForURL(url, host) {{
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)))
}

View File

@ -26,6 +26,7 @@ use jsonrpc_http_server::{self as http, Host, DomainsValidation};
use devtools::http_client;
use hash_fetch::urlhint::ContractClient;
use fetch::{Fetch, Client as FetchClient};
use futures_cpupool::CpuPool;
use parity_reactor::Remote;
use {Middleware, SyncStatus, WebProxyTokens};
@ -38,6 +39,12 @@ use self::fetch::FakeFetch;
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() {
// Initialize logger
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>) {
init_server(|builder| {
builder.sync_status(Arc::new(|| true))
builder.sync_status(Arc::new(FakeSync(true)))
}, Default::default(), Remote::new_sync())
}
@ -148,7 +155,7 @@ impl ServerBuilder {
ServerBuilder {
dapps_path: dapps_path.as_ref().to_owned(),
registrar: registrar,
sync_status: Arc::new(|| false),
sync_status: Arc::new(FakeSync(false)),
web_proxy_tokens: Arc::new(|_| None),
signer_address: None,
allowed_hosts: DomainsValidation::Disabled,
@ -248,8 +255,11 @@ impl Server {
fetch: F,
) -> Result<Server, http::Error> {
let middleware = Middleware::dapps(
"pool.ntp.org:123",
CpuPool::new(4),
remote,
signer_address,
vec![],
dapps_path,
extra_dapps,
DAPPS_DOMAIN.into(),
@ -290,4 +300,3 @@ impl Drop for Server {
self.server.take().unwrap().close()
}
}

View File

@ -25,7 +25,7 @@ use std::mem;
use std::ptr;
use sha3;
use std::slice;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::io::{self, Read, Write};
use std::fs::{self, File};
@ -86,6 +86,7 @@ impl Node {
pub type H256 = [u8; 32];
pub struct Light {
cache_dir: PathBuf,
block_number: u64,
cache: Vec<Node>,
seed_compute: Mutex<SeedHashCompute>,
@ -94,8 +95,8 @@ pub struct Light {
/// Light cache structure
impl Light {
/// Create a new light cache for a given block number
pub fn new(block_number: u64) -> Light {
light_new(block_number)
pub fn new<T: AsRef<Path>>(cache_dir: T, block_number: u64) -> Light {
light_new(cache_dir, block_number)
}
/// Calculate the light boundary data
@ -105,17 +106,15 @@ impl Light {
light_compute(self, header_hash, nonce)
}
pub fn file_path(seed_hash: H256) -> PathBuf {
let mut home = ::std::env::home_dir().unwrap();
home.push(".ethash");
home.push("light");
home.push(to_hex(&seed_hash));
home
pub fn file_path<T: AsRef<Path>>(cache_dir: T, seed_hash: H256) -> PathBuf {
let mut cache_dir = cache_dir.as_ref().to_path_buf();
cache_dir.push(to_hex(&seed_hash));
cache_dir
}
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 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 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) };
file.read_exact(buf)?;
Ok(Light {
block_number,
cache_dir: cache_dir.as_ref().to_path_buf(),
cache: nodes,
block_number: block_number,
seed_compute: Mutex::new(seed_compute),
})
}
pub fn to_file(&self) -> io::Result<PathBuf> {
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 {
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() {
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 seedhash = seed_compute.get_seedhash(block_number);
let cache_size = get_cache_size(block_number);
if cache_size % NODE_BYTES != 0 {
panic!("Unaligned cache size");
}
assert!(cache_size % NODE_BYTES == 0, "Unaligned cache size");
let num_nodes = cache_size / NODE_BYTES;
let mut nodes = Vec::with_capacity(num_nodes);
@ -372,8 +372,9 @@ fn light_new(block_number: u64) -> Light {
}
Light {
block_number,
cache_dir: cache_dir.as_ref().to_path_buf(),
cache: nodes,
block_number: block_number,
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 nonce = 0xd7b3ac70a301a249;
// difficulty = 0x085657254bd9u64;
let light = Light::new(486382);
let light = Light::new(&::std::env::temp_dir(), 486382);
let result = light_compute(&light, &hash, nonce);
assert_eq!(result.mix_hash[..], mix_hash[..]);
assert_eq!(result.value[..], boundary[..]);
@ -471,15 +472,16 @@ fn test_seed_compute_after_newer() {
#[test]
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());
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(&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());
}

View File

@ -25,6 +25,7 @@ extern crate log;
mod compute;
use std::mem;
use std::path::{Path, PathBuf};
use compute::Light;
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.
pub struct EthashManager {
cache: Mutex<LightCache>,
cache_dir: PathBuf,
}
impl EthashManager {
/// Create a new new instance of ethash manager
pub fn new() -> EthashManager {
pub fn new<T: AsRef<Path>>(cache_dir: T) -> EthashManager {
EthashManager {
cache_dir: cache_dir.as_ref().to_path_buf(),
cache: Mutex::new(LightCache {
recent_epoch: None,
recent: None,
@ -88,11 +91,11 @@ impl EthashManager {
};
match light {
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),
Err(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() {
warn!("Light cache file write error: {}", e);
}
@ -112,7 +115,7 @@ impl EthashManager {
#[test]
fn test_lru() {
let ethash = EthashManager::new();
let ethash = EthashManager::new(&::std::env::temp_dir());
let hash = [0u8; 32];
ethash.compute_light(1, &hash, 1);
ethash.compute_light(50000, &hash, 1);

View File

@ -52,6 +52,8 @@ semver = "0.6"
stats = { path = "../util/stats" }
time = "0.1"
transient-hashmap = "0.4"
parity-wasm = "0.12"
wasm-utils = { git = "https://github.com/paritytech/wasm-utils" }
[dev-dependencies]
native-contracts = { path = "native_contracts", features = ["test_contracts"] }

View File

@ -26,7 +26,7 @@ use ethcore::receipt::Receipt;
use stats::Corpus;
use time::{SteadyTime, Duration};
use util::{U256, H256};
use util::{U256, H256, HeapSizeOf};
use util::cache::MemoryLruCache;
/// Configuration for how much data to cache.
@ -153,6 +153,22 @@ impl Cache {
pub fn set_gas_price_corpus(&mut self, corpus: Corpus<U256>) {
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)]

View File

@ -44,7 +44,7 @@ mod header_chain;
mod service;
/// Configuration for the light client.
#[derive(Debug, Default, Clone)]
#[derive(Debug, Clone)]
pub struct Config {
/// Verification queue config.
pub queue: queue::Config,
@ -56,6 +56,21 @@ pub struct Config {
pub db_compaction: CompactionProfile,
/// Should db have WAL enabled?
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.
@ -109,6 +124,9 @@ pub trait LightChainClient: Send + Sync {
/// Get the EIP-86 transition block number.
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.
@ -141,6 +159,7 @@ pub struct Client {
import_lock: Mutex<()>,
db: Arc<KeyValueDB>,
listeners: RwLock<Vec<Weak<LightChainNotify>>>,
verify_full: bool,
}
impl Client {
@ -156,6 +175,7 @@ impl Client {
import_lock: Mutex::new(()),
db: db,
listeners: RwLock::new(vec![]),
verify_full: config.verify_full,
})
}
@ -263,6 +283,14 @@ impl Client {
for verified_header in self.queue.drain(MAX) {
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 pending = match self.chain.insert(&mut tx, verified_header) {
Ok(pending) => {
@ -273,14 +301,16 @@ impl Client {
Err(e) => {
debug!(target: "client", "Error importing header {:?}: {}", (num, hash), e);
bad.push(hash);
break;
continue;
}
};
self.db.write_buffered(tx);
self.chain.apply_pending(pending);
if let Err(e) = self.db.flush() {
panic!("Database flush failed: {}. Check disk health and space.", e);
}
}
if let Err(e) = self.db.flush() {
panic!("Database flush failed: {}. Check disk health and space.", e);
}
self.queue.mark_as_bad(&bad);
@ -291,7 +321,7 @@ impl Client {
/// Get a report about blocks imported.
pub fn report(&self) -> ClientReport {
::std::mem::replace(&mut *self.report.write(), ClientReport::default())
self.report.read().clone()
}
/// 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 {
@ -414,4 +475,8 @@ impl LightChainClient for Client {
fn eip86_transition(&self) -> u64 {
self.engine().params().eip86_transition
}
fn report(&self) -> ClientReport {
Client::report(self)
}
}

View File

@ -54,10 +54,10 @@
"0x00521965e7bd230323c423d96c657db5b79d099f": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }
},
"nodes": [
"enode://c005dd308256c60fab247813d8bf6d6e81f9cd354287837eb1c2fcf294adaa913a3208e88900ef5c55a8cba7042c301d80503edec2ad3f92a72e241ee6743854@192.241.230.87:30303",
"enode://48caeceb2724f2f71406990aa81efe87f8c53f26441d891473da2ae50cc138f238addc0e46b5aee240db55de8c711daac53d7b32a3f13e30edb86a3ca7c2700b@138.68.143.220:30303",
"enode://85705212fd28ebdd56669fb55e958feb9d81f74fe76c82f867564b6c2995e69f596df0f588eba16f1a43b69ce06485d68231a0c83fed8469b41eba0e390c126f@139.59.146.42:30303",
"enode://2aa81bd0a761cd4f02c934dcf3f81c5b65953e51ab5ba03ceb1f125eb06418a1cdffb1c9d01871aa7bd456f3fce35e745608189ad1164f72b2161634b0c3f6ea@188.166.240.190:30303",
"enode://c5900cdd6d20795d58372f42dfbab9d664c27bb97e9c27972741942736e919122f9bac28e74cbc58e4ff195475ea90d9880b71a37af5b5a8cb41d843f765cff8@174.138.79.48:30303"
"enode://0518a3d35d4a7b3e8c433e7ffd2355d84a1304ceb5ef349787b556197f0c87fad09daed760635b97d52179d645d3e6d16a37d2cc0a9945c2ddf585684beb39ac@40.68.248.100:30303",
"enode://dcf984764db421fa0cd8dc7fc02ae378545723abb94d179f55325514cc30185eaea3dcefde6e358b7cdbe970c50b7c49e841618713a9a72d6f3f59ad9949ec6b@52.165.239.18:30303",
"enode://7e2e7f00784f516939f94e22bdc6cf96153603ca2b5df1c7cc0f90a38e7a2f218ffb1c05b156835e8b49086d11fdd1b3e2965be16baa55204167aa9bf536a4d9@52.243.47.56:30303",
"enode://d51b3e98bf35addf2f1d0ea1ffc90483e24d7c60b0fb3be1701e818f3d6778c06e53fdec737a534fe222956296f9d6e909baa025916a94601897e5c7136a7d95@40.71.221.215:30303",
"enode://419d42e300e8fd379ff6d045d93d7e66a091441e7b3c9f1d3d10088d8634ad37721e6bf86148f78c3f1b9f1360dc566ca8ee830b2d2079bc9f7171ea6152bb64@52.166.117.77:30303"
]
}

@ -0,0 +1 @@
Subproject commit 9ed6304313fa949ed92aa0570fb2bc759fb6dc58

View File

@ -39,6 +39,16 @@ impl ActionValue {
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).

View File

@ -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 {
last_activity: Option<Instant>,
last_autosleep: Option<Instant>,
@ -1702,6 +1718,33 @@ impl MiningBlockChainClient for Client {
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 {
&self.factories.vm
}

View File

@ -44,7 +44,7 @@ use types::mode::Mode;
use types::pruning_info::PruningInfo;
use verification::queue::QueueInfo;
use block::{OpenBlock, SealedBlock};
use block::{OpenBlock, SealedBlock, ClosedBlock};
use executive::Executed;
use error::CallError;
use trace::LocalizedTrace;
@ -381,6 +381,10 @@ impl MiningBlockChainClient for TestBlockChainClient {
open_block
}
fn reopen_block(&self, block: ClosedBlock) -> OpenBlock {
block.reopen(&*self.spec.engine)
}
fn vm_factory(&self) -> &EvmFactory {
&self.vm_factory
}

View File

@ -19,7 +19,7 @@ use util::{U256, Address, H256, H2048, Bytes, Itertools};
use util::hashdb::DBValue;
use blockchain::TreeRoute;
use verification::queue::QueueInfo as BlockQueueInfo;
use block::{OpenBlock, SealedBlock};
use block::{OpenBlock, SealedBlock, ClosedBlock};
use header::{BlockNumber};
use transaction::{LocalizedTransaction, PendingTransaction, SignedTransaction};
use transaction_import::TransactionImportResult;
@ -288,6 +288,9 @@ pub trait MiningBlockChainClient: BlockChainClient {
extra_data: Bytes
) -> OpenBlock;
/// Reopens an OpenBlock and updates uncles.
fn reopen_block(&self, block: ClosedBlock) -> OpenBlock;
/// Returns EvmFactory.
fn vm_factory(&self) -> &EvmFactory;

View File

@ -266,7 +266,7 @@ mod tests {
/// Create a new test chain spec with `BasicAuthority` consensus engine.
fn new_test_authority() -> Spec {
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]

View File

@ -376,6 +376,11 @@ pub trait Engine : Sync + Send {
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.
fn create_address_scheme(&self, number: BlockNumber) -> CreateContractAddress {
if number >= self.params().eip86_transition {
@ -386,7 +391,6 @@ pub trait Engine : Sync + Send {
}
}
/// Common engine utilities
pub mod common {
use block::ExecutedBlock;

View File

@ -129,6 +129,8 @@ pub enum BlockError {
UncleIsBrother(OutOfBounds<BlockNumber>),
/// An uncle is already in the chain.
UncleInChain(H256),
/// An uncle is included twice.
DuplicateUncle(H256),
/// An uncle has a parent not in the chain.
UncleParentNotInChain(H256),
/// 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),
UncleIsBrother(ref oob) => format!("Uncle from same generation as block. {}", oob),
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),
InvalidStateRoot(ref mis) => format!("Invalid state root in header: {}", mis),
InvalidGasUsed(ref mis) => format!("Invalid gas used in header: {}", mis),

View File

@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License
// 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 util::*;
use block::*;
@ -24,7 +25,7 @@ use header::{Header, BlockNumber};
use state::CleanupMode;
use spec::CommonParams;
use transaction::UnverifiedTransaction;
use engines::Engine;
use engines::{self, Engine};
use evm::Schedule;
use ethjson;
use rlp::{self, UntrustedRlp};
@ -147,12 +148,17 @@ pub struct Ethash {
impl Ethash {
/// 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 {
params: params,
ethash_params: ethash_params,
builtins: builtins,
pow: EthashManager::new(),
params,
ethash_params,
builtins,
pow: EthashManager::new(cache_dir),
})
}
}
@ -165,7 +171,7 @@ impl Ethash {
// for any block in the chain.
// in the future, we might move the Ethash epoch
// 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_heavy(&self, header: &Header) -> Result<(), Error> {
self.verify_block_unordered(header, None)
@ -262,7 +268,7 @@ impl Engine for Arc<Ethash> {
_begins_epoch: bool,
) -> Result<(), Error> {
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 {
let state = block.fields_mut().state;
for child in &self.ethash_params.dao_hardfork_accounts {
@ -404,8 +410,8 @@ impl Engine for Arc<Ethash> {
Ok(())
}
fn epoch_verifier<'a>(&self, _header: &Header, _proof: &'a [u8]) -> ::engines::ConstructedVerifier<'a> {
::engines::ConstructedVerifier::Trusted(Box::new(self.clone()))
fn epoch_verifier<'a>(&self, _header: &Header, _proof: &'a [u8]) -> engines::ConstructedVerifier<'a> {
engines::ConstructedVerifier::Trusted(Box::new(self.clone()))
}
fn snapshot_components(&self) -> Option<Box<::snapshot::SnapshotComponents>> {
@ -558,13 +564,18 @@ mod tests {
use engines::Engine;
use error::{BlockError, Error};
use header::Header;
use spec::Spec;
use super::super::{new_morden, new_homestead_test};
use super::{Ethash, EthashParams, PARITY_GAS_LIMIT_DETERMINANT, ecip1017_eras_block_reward};
use rlp;
fn test_spec() -> Spec {
new_morden(&::std::env::temp_dir())
}
#[test]
fn on_close_block() {
let spec = new_morden();
let spec = test_spec();
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
@ -576,7 +587,7 @@ mod tests {
#[test]
fn on_close_block_with_uncle() {
let spec = new_morden();
let spec = test_spec();
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
@ -594,14 +605,14 @@ mod tests {
#[test]
fn has_valid_metadata() {
let engine = new_morden().engine;
let engine = test_spec().engine;
assert!(!engine.name().is_empty());
assert!(engine.version().major >= 1);
}
#[test]
fn can_return_schedule() {
let engine = new_morden().engine;
let engine = test_spec().engine;
let schedule = engine.schedule(10000000);
assert!(schedule.stack_limit > 0);
@ -611,8 +622,8 @@ mod tests {
#[test]
fn can_do_seal_verification_fail() {
let engine = new_morden().engine;
//let engine = Ethash::new_test(new_morden());
let engine = test_spec().engine;
//let engine = Ethash::new_test(test_spec());
let header: Header = Header::default();
let verify_result = engine.verify_block_basic(&header, None);
@ -626,7 +637,7 @@ mod tests {
#[test]
fn can_do_difficulty_verification_fail() {
let engine = new_morden().engine;
let engine = test_spec().engine;
let mut header: Header = Header::default();
header.set_seal(vec![rlp::encode(&H256::zero()).into_vec(), rlp::encode(&H64::zero()).into_vec()]);
@ -641,7 +652,7 @@ mod tests {
#[test]
fn can_do_proof_of_work_verification_fail() {
let engine = new_morden().engine;
let engine = test_spec().engine;
let mut header: Header = Header::default();
header.set_seal(vec![rlp::encode(&H256::zero()).into_vec(), rlp::encode(&H64::zero()).into_vec()]);
header.set_difficulty(U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaa").unwrap());
@ -657,7 +668,7 @@ mod tests {
#[test]
fn can_do_seal_unordered_verification_fail() {
let engine = new_morden().engine;
let engine = test_spec().engine;
let header: Header = Header::default();
let verify_result = engine.verify_block_unordered(&header, None);
@ -671,7 +682,7 @@ mod tests {
#[test]
fn can_do_seal256_verification_fail() {
let engine = new_morden().engine;
let engine = test_spec().engine;
let mut header: Header = Header::default();
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);
@ -685,7 +696,7 @@ mod tests {
#[test]
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();
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());
@ -701,7 +712,7 @@ mod tests {
#[test]
fn can_verify_block_family_genesis_fail() {
let engine = new_morden().engine;
let engine = test_spec().engine;
let header: Header = Header::default();
let parent_header: Header = Header::default();
@ -716,7 +727,7 @@ mod tests {
#[test]
fn can_verify_block_family_difficulty_fail() {
let engine = new_morden().engine;
let engine = test_spec().engine;
let mut header: Header = Header::default();
header.set_number(2);
let mut parent_header: Header = Header::default();
@ -733,7 +744,7 @@ mod tests {
#[test]
fn can_verify_block_family_gas_fail() {
let engine = new_morden().engine;
let engine = test_spec().engine;
let mut header: Header = Header::default();
header.set_number(2);
header.set_difficulty(U256::from_str("0000000000000000000000000000000000000000000000000000000000020000").unwrap());
@ -763,7 +774,7 @@ mod tests {
fn difficulty_frontier() {
let spec = new_homestead_test();
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();
parent_header.set_number(1000000);
@ -781,7 +792,7 @@ mod tests {
fn difficulty_homestead() {
let spec = new_homestead_test();
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();
parent_header.set_number(1500000);
@ -838,7 +849,7 @@ mod tests {
ecip1010_pause_transition: 3000000,
..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();
parent_header.set_number(3500000);
@ -872,7 +883,7 @@ mod tests {
ecip1010_continue_transition: 5000000,
..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();
parent_header.set_number(5000102);
@ -917,7 +928,8 @@ mod tests {
#[test]
fn gas_limit_is_multiple_of_determinant() {
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 header = Header::new();
header.set_number(1);
@ -961,7 +973,7 @@ mod tests {
fn difficulty_max_timestamp() {
let spec = new_homestead_test();
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();
parent_header.set_number(1000000);
@ -989,7 +1001,7 @@ mod tests {
header.set_number(parent_header.number() + 1);
header.set_gas_limit(100_001.into());
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());
parent_header.set_number(9);
@ -1044,7 +1056,7 @@ mod tests {
nonce: U256::zero(),
}.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(&tx2, &header).is_ok());

View File

@ -27,6 +27,7 @@ pub mod denominations;
pub use self::ethash::{Ethash};
pub use self::denominations::*;
use std::path::Path;
use super::spec::*;
/// 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.
pub const FORK_SUPPORTED_KOVAN: u64 = 0;
fn load(b: &[u8]) -> Spec {
Spec::load(b).expect("chain spec is invalid")
fn load<'a, T: 'a + Into<Option<&'a Path>>>(cache_dir: T, b: &[u8]) -> Spec {
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.
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.
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.
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.
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.
pub fn new_kovan() -> Spec { load(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")) }
pub fn new_kovan(cache_dir: &Path) -> Spec { load(cache_dir, include_bytes!("../../res/ethereum/kovan.json")) }
/// 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.
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)]
mod tests {
@ -94,7 +100,7 @@ mod tests {
#[test]
fn ensure_db_good() {
let spec = new_morden();
let spec = new_morden(&::std::env::temp_dir());
let engine = &spec.engine;
let genesis_header = spec.genesis_header();
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
@ -109,7 +115,7 @@ mod tests {
#[test]
fn morden() {
let morden = new_morden();
let morden = new_morden(&::std::env::temp_dir());
assert_eq!(morden.state_root(), "f3f4696bbf3b3b07775128eb7a3763279a394e382130f27c21e70233e04946a9".into());
let genesis = morden.genesis_block();
@ -120,7 +126,7 @@ mod tests {
#[test]
fn frontier() {
let frontier = new_foundation();
let frontier = new_foundation(&::std::env::temp_dir());
assert_eq!(frontier.state_root(), "d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544".into());
let genesis = frontier.genesis_block();
@ -128,4 +134,23 @@ mod tests {
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();
}
}

View File

@ -21,6 +21,7 @@ use util::{U128, U256, U512, trie};
use action_params::ActionParams;
use evm::Ext;
use builtin;
use super::wasm;
/// Evm errors.
#[derive(Debug, Clone, PartialEq)]
@ -66,6 +67,8 @@ pub enum Error {
MutableCallInStaticContext,
/// Likely to cause consensus issues.
Internal(String),
/// Wasm runtime error
Wasm(String),
}
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 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::Error::*;
@ -92,6 +101,7 @@ impl fmt::Display for Error {
BuiltIn(name) => write!(f, "Built-in failed: {}", name),
Internal(ref msg) => write!(f, "Internal error: {}", msg),
MutableCallInStaticContext => write!(f, "Mutable call in static context"),
Wasm(ref msg) => write!(f, "Internal error: {}", msg),
}
}
}

View File

@ -129,8 +129,11 @@ pub trait Ext {
/// Increments sstore refunds count by 1.
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.
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)>) {}

View File

@ -111,6 +111,7 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
self.mem.clear();
let mut informant = informant::EvmInformant::new(ext.depth());
let mut do_trace = true;
let code = &params.code.as_ref().expect("exec always called with code; qed");
let mut valid_jump_destinations = None;
@ -124,13 +125,17 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
let instruction = code[reader.position];
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];
self.verify_instruction(ext, instruction, info, &stack)?;
// Calculate gas cost
let requirements = gasometer.requirements(ext, instruction, info, &stack, self.mem.size())?;
// TODO: make compile-time removable if too much of a performance hit.
let trace_executed = ext.trace_prepare_execute(reader.position - 1, instruction, &requirements.gas_cost.as_u256());
if do_trace {
ext.trace_prepare_execute(reader.position - 1, instruction, requirements.gas_cost.as_u256());
}
gasometer.verify_gas(&requirements.gas_cost)?;
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) });
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)),
false => (None, None),
};
@ -155,7 +160,7 @@ impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
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);
}

View File

@ -22,6 +22,7 @@ pub mod interpreter;
#[macro_use]
pub mod factory;
pub mod schedule;
pub mod wasm;
mod vmtype;
mod instructions;

View File

@ -39,13 +39,13 @@ pub enum FakeCallType {
#[derive(PartialEq, Eq, Hash, Debug)]
pub struct FakeCall {
call_type: FakeCallType,
gas: U256,
sender_address: Option<Address>,
receive_address: Option<Address>,
value: Option<U256>,
data: Bytes,
code_address: Option<Address>,
pub call_type: FakeCallType,
pub gas: U256,
pub sender_address: Option<Address>,
pub receive_address: Option<Address>,
pub value: Option<U256>,
pub data: Bytes,
pub code_address: Option<Address>,
}
/// Fake externalities test structure.
@ -53,17 +53,17 @@ pub struct FakeCall {
/// Can't do recursive calls.
#[derive(Default)]
pub struct FakeExt {
pub store: HashMap<H256, H256>,
pub suicides: HashSet<Address>,
pub calls: HashSet<FakeCall>,
sstore_clears: usize,
depth: usize,
store: HashMap<H256, H256>,
blockhashes: HashMap<U256, H256>,
codes: HashMap<Address, Arc<Bytes>>,
logs: Vec<FakeLogEntry>,
_suicides: HashSet<Address>,
info: EnvInfo,
schedule: Schedule,
balances: HashMap<Address, U256>,
calls: HashSet<FakeCall>,
}
// similar to the normal `finalize` function, but ignoring NeedsReturn.
@ -173,8 +173,9 @@ impl Ext for FakeExt {
unimplemented!();
}
fn suicide(&mut self, _refund_address: &Address) -> evm::Result<()> {
unimplemented!();
fn suicide(&mut self, refund_address: &Address) -> evm::Result<()> {
self.suicides.insert(refund_address.clone());
Ok(())
}
fn schedule(&self) -> &Schedule {

View 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
View 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
View 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),
}
}

View 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 }
}

View 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)?)
}
}

View 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)
}
}
}
}

View 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));
}

View File

@ -22,7 +22,7 @@ use engines::Engine;
use types::executed::CallType;
use env_info::EnvInfo;
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 trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer};
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`
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
pub fn contract_address(address_scheme: CreateContractAddress, sender: &Address, nonce: &U256, code: &[u8]) -> (Address, Option<H256>) {
use rlp::RlpStream;
@ -72,6 +74,20 @@ pub struct TransactOptions {
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.
pub struct Executive<'a, B: 'a + StateBackend, E: 'a + Engine + ?Sized> {
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 mut ext = self.as_externalities(OriginInfo::from(&params), unconfirmed_substate, output_policy, tracer, vm_tracer, static_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, &params).exec(params, &mut ext).finalize(ext);
}
// Start in new thread to reset stack
// TODO [todr] No thread builder yet, so we need to reset once for a while
// https://github.com/aturon/crossbeam/issues/16
crossbeam::scope(|scope| {
let engine = self.engine;
let vm_factory = self.state.vm_factory();
let mut ext = self.as_externalities(OriginInfo::from(&params), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call);
scope.spawn(move || {
vm_factory.create(params.gas).exec(params, &mut ext).finalize(ext)
executor(engine, &vm_factory, &params).exec(params, &mut ext).finalize(ext)
})
}).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)
};
vm_tracer.done_subtrace(subvmtracer, res.is_ok());
vm_tracer.done_subtrace(subvmtracer);
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)
};
vm_tracer.done_subtrace(subvmtracer, res.is_ok());
vm_tracer.done_subtrace(subvmtracer);
match res {
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::StackUnderflow {..})
| Err(evm::Error::BuiltIn {..})
| Err(evm::Error::Wasm {..})
| Err(evm::Error::OutOfStack {..})
| Err(evm::Error::MutableCallInStaticContext)
| Ok(FinalizationResult { apply_state: false, .. }) => {

View File

@ -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();
}
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)
}

View File

@ -105,6 +105,8 @@ extern crate semver;
extern crate stats;
extern crate time;
extern crate transient_hashmap;
extern crate parity_wasm;
extern crate wasm_utils;
#[macro_use]
extern crate log;

View File

@ -88,6 +88,8 @@ pub struct MinerOptions {
pub reseal_on_external_tx: bool,
/// Reseal on receipt of new local transactions.
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.
pub reseal_min_period: Duration,
/// Maximum period between blocks (enables force sealing after that).
@ -119,6 +121,7 @@ impl Default for MinerOptions {
force_sealing: false,
reseal_on_external_tx: false,
reseal_on_own_tx: true,
reseal_on_uncle: false,
tx_gas_limit: !U256::zero(),
tx_queue_size: 1024,
tx_queue_gas_limit: GasLimit::Auto,
@ -347,7 +350,7 @@ impl Miner {
Some(old_block) => {
trace!(target: "miner", "prepare_block: Already have previous work; updating and returning");
// add transactions to old_block
old_block.reopen(&*self.engine)
chain.reopen_block(old_block)
}
None => {
// block not found - create it.
@ -366,7 +369,6 @@ impl Miner {
let mut transactions_to_penalize = HashSet::new();
let block_number = open_block.block().fields().header.number();
// TODO Push new uncles too.
let mut tx_count: usize = 0;
let tx_total = transactions.len();
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");
// 1. We ignore blocks that were `imported` (because it means that they are not in canon-chain, and transactions
// should be still available in the queue.
// 1. We ignore blocks that were `imported` unless resealing on new uncles is enabled.
// 2. We ignore blocks that are `invalid` because it doesn't have any meaning in terms of the transactions that
// are in those blocks
@ -1192,7 +1193,7 @@ impl MinerService for Miner {
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. |
// | Make sure to release the locks before calling that method. |
@ -1312,6 +1313,7 @@ mod tests {
force_sealing: false,
reseal_on_external_tx: false,
reseal_on_own_tx: true,
reseal_on_uncle: false,
reseal_min_period: Duration::from_secs(5),
reseal_max_period: Duration::from_secs(120),
tx_gas_limit: !U256::zero(),

View File

@ -32,7 +32,7 @@
//! use ethcore::miner::{Miner, MinerService};
//!
//! fn main() {
//! let miner: Miner = Miner::with_spec(&ethereum::new_foundation());
//! let miner: Miner = Miner::with_spec(&ethereum::new_foundation(&env::temp_dir()));
//! // get status
//! assert_eq!(miner.status().transactions_in_pending_queue, 0);
//!

View File

@ -59,7 +59,7 @@ lazy_static! {
/// `native_contracts::test_contracts::ValidatorSet` provides a native wrapper for the ABi.
fn spec_fixed_to_contract() -> Spec {
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

View File

@ -80,9 +80,11 @@ pub struct CommonParams {
/// Number of first block where dust cleanup rules (EIP-168 and EIP169) begin.
pub dust_protection_transition: BlockNumber,
/// Nonce cap increase per block. Nonce cap is only checked if dust protection is enabled.
pub nonce_cap_increment : u64,
pub nonce_cap_increment: u64,
/// 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 {
@ -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),
nonce_cap_increment: p.nonce_cap_increment.map_or(64, Into::into),
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,
}
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 g = Genesis::from(s.genesis);
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 {
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(),
nodes: s.nodes.unwrap_or_else(Vec::new),
parent_hash: g.parent_hash,
@ -195,18 +198,26 @@ fn load_from(s: ethjson::spec::Spec) -> Result<Spec, Error> {
macro_rules! load_bundled {
($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 {
/// 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.
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 {
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::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::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."),
@ -397,13 +408,13 @@ impl Spec {
/// Loads spec from json file. Provide factories for executing contracts and ensuring
/// 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 {
format!("Spec json is invalid: {}", f)
}
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.
@ -453,7 +464,20 @@ mod tests {
// https://github.com/paritytech/parity/issues/1840
#[test]
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]

View File

@ -52,7 +52,7 @@ fn imports_from_empty() {
#[test]
fn should_return_registrar() {
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 client_db = Arc::new(Database::open(&db_config, dir.as_path().to_str().unwrap()).unwrap());

View File

@ -192,14 +192,15 @@ impl 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 {
pc: pc,
instruction: instruction,
gas_cost: gas_cost.clone(),
gas_cost: gas_cost,
executed: None,
});
true
}
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);
}

View File

@ -87,18 +87,23 @@ pub trait Tracer: Send {
/// Used by executive to build VM traces.
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)>) {}
/// Spawn subtracer which will be used to trace deeper levels of execution.
fn prepare_subtrace(&self, code: &[u8]) -> Self where Self: Sized;
/// 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.
fn drain(self) -> Option<VMTrace>;

View File

@ -71,18 +71,15 @@ impl Tracer for NoopTracer {
pub struct NoopVMTracer;
impl VMTracer for NoopVMTracer {
/// Trace the preparation to execute a single instruction.
fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _gas_cost: &U256) -> bool { false }
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) {}
/// 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)>) {}
/// Spawn subtracer which will be used to trace deeper levels of execution.
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, _is_successful: bool) {}
fn done_subtrace(&mut self, _sub: Self) {}
/// Consumes self and returns all VM traces.
fn drain(self) -> Option<VMTrace> { None }
}

View File

@ -42,6 +42,8 @@ pub enum Error {
Internal,
/// When execution tries to modify the state in static context
MutableCallInStaticContext,
/// Wasm error
Wasm,
}
impl<'a> From<&'a EvmError> for Error {
@ -53,6 +55,7 @@ impl<'a> From<&'a EvmError> for Error {
EvmError::StackUnderflow { .. } => Error::StackUnderflow,
EvmError::OutOfStack { .. } => Error::OutOfStack,
EvmError::BuiltIn { .. } => Error::BuiltIn,
EvmError::Wasm { .. } => Error::Wasm,
EvmError::Internal(_) => Error::Internal,
EvmError::MutableCallInStaticContext => Error::MutableCallInStaticContext,
}
@ -75,6 +78,7 @@ impl fmt::Display for Error {
StackUnderflow => "Stack underflow",
OutOfStack => "Out of stack",
BuiltIn => "Built-in failed",
Wasm => "Wasm runtime error",
Internal => "Internal error",
MutableCallInStaticContext => "Mutable Call In Static Context",
};
@ -94,6 +98,7 @@ impl Encodable for Error {
Internal => 5,
BuiltIn => 6,
MutableCallInStaticContext => 7,
Wasm => 8,
};
s.append_internal(&value);
@ -113,6 +118,7 @@ impl Decodable for Error {
5 => Ok(Internal),
6 => Ok(BuiltIn),
7 => Ok(MutableCallInStaticContext),
8 => Ok(Wasm),
_ => Err(DecoderError::Custom("Invalid error type")),
}
}

View File

@ -17,7 +17,7 @@
//! Verification queue info types
/// Verification queue status
#[derive(Debug)]
#[derive(Debug, Clone)]
#[cfg_attr(feature = "ipc", binary)]
pub struct VerificationQueueInfo {
/// Number of queued items pending verification

View File

@ -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>()) {
let uncle = uncle?;
if excluded.contains(&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()
// 1 2
// 2
@ -180,6 +185,7 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &
verify_parent(&uncle, &uncle_parent)?;
engine.verify_block_family(&uncle, &uncle_parent, Some(bytes))?;
verified.insert(uncle.hash());
}
}
Ok(())
@ -568,6 +574,11 @@ mod tests {
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() }));
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
}

View File

@ -81,13 +81,18 @@ impl vm::Informant 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.instruction = instruction;
self.gas_cost = *gas_cost;
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)>) {
let info = evm::INSTRUCTIONS[self.instruction as usize];
@ -127,17 +132,9 @@ impl trace::VMTracer for Informant {
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 {
// 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();
let gas_used = sub.gas_used;
trace::VMTracer::trace_executed(&mut sub, gas_used, &[], None, None);

View File

@ -44,6 +44,6 @@ impl vm::Informant for Informant {
impl trace::VMTracer for Informant {
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 }
}

View File

@ -134,10 +134,10 @@ impl Args {
Ok(match self.flag_spec {
Some(ref filename) => {
let file = fs::File::open(filename).map_err(|e| format!("{}", e))?;
spec::Spec::load(file)?
spec::Spec::load(::std::env::temp_dir(), file)?
},
None => {
spec::Spec::new_instant()
ethcore::ethereum::new_foundation(&::std::env::temp_dir())
},
})
}

View File

@ -124,6 +124,7 @@
"istanbul": "1.0.0-alpha.2",
"jsdom": "9.11.0",
"json-loader": "0.5.4",
"markdown-loader": "2.0.0",
"mocha": "3.2.0",
"mock-local-storage": "1.0.2",
"mock-socket": "6.0.4",

View File

@ -94,6 +94,7 @@ class FrameSecureApi extends SecureApi {
const transport = window.secureTransport || new FakeTransport();
const uiUrl = transport.uiUrl || 'http://127.0.0.1:8180';
transport.uiUrlWithProtocol = uiUrl;
transport.uiUrl = uiUrl.replace('http://', '').replace('https://', '');
const api = new FrameSecureApi(transport);

View File

@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import { observer } from 'mobx-react';
import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl';
@ -21,6 +22,7 @@ import { Form, Input, InputAddress, QrScan } from '~/ui';
import ChangeVault from '../ChangeVault';
@observer
export default class NewQr extends Component {
static propTypes = {
createStore: PropTypes.object.isRequired,

View File

@ -16,10 +16,17 @@
import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl';
import ReactMarkdown from 'react-markdown';
import { Checkbox } from 'material-ui';
import styles from '../firstRun.css';
let tnc = '';
if (process.env.NODE_ENV !== 'test') {
tnc = require('./tnc.md');
}
export default class TnC extends Component {
static propTypes = {
hasAccepted: PropTypes.bool.isRequired,
@ -31,139 +38,10 @@ export default class TnC extends Component {
return (
<div className={ styles.tnc }>
<h1>SECURITY WARNINGS</h1>
<ul>
<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>
<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 users 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 Limiteds open source software product (Parity). Prior to any use of the Parity or any of Parity Technologies Limiteds products (Paritys 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 Paritys or Paritys 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 Paritys 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 Paritys 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 Paritys 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, Paritys 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 Paritys 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 Paritys Products you may be exposed to Content that you may find offensive, indecent or objectionable and that, in this respect, you use Parity or Paritys 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 Paritys 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 Paritys Products, including any intellectual property rights which subsist in Parity and Paritys 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 Paritys 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 Paritys 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 Paritys 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, Paritys 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 Paritys Products, grant a security interest in or over your rights to use the Paritys Products, or otherwise transfer any part of your rights to use the Paritys 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 Paritys 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 Paritys 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 PARITYS PRODUCTS AT THE USERS 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 PARITYS PRODUCTS IS AT YOUR SOLE RISK AND THAT PARITYS 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 PARITYS PRODUCTS WILL MEET YOUR REQUIREMENTS,</p>
<p>(B) YOUR USE OF PARITY OR PARITYS 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 PARITYS 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 PARITYS PRODUCTS WILL BE CORRECTED.</p>
<p>ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF PARITY OR PARITYS 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 PARITYS 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 PARITYS PRODUCTS;</p>
<p>(II) ANY CHANGES WHICH PARITY MAY MAKE TO PARITYS PRODUCTS, OR FOR ANY PERMANENT OR TEMPORARY CESSATION IN THE PROVISION OF PARITYS PRODUCTS (OR ANY FEATURES WITHIN PARITYS 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 PARITYS 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 PARITYS 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 Paritys 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 Paritys 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 Paritys Product.</p>
<p>You understand and agree that if you use Parity or Paritys 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 Paritys 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 Paritys 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 Paritys Products.</p>
<p>You agree that Parity may provide you with notices, including those regarding changes to the Terms, by postings on the affected Paritys 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 Paritys 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 Courts decision to have three arbitrators; in the case of Respondent, measured from receipt of notification of Claimants 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 Paritys 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 Paritys Products software licence terms.</p>
<ReactMarkdown
className={ styles.markdown }
source={ tnc }
/>
<Checkbox
className={ styles.accept }
label={

View 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&#39;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 (&quot;Terms&quot;) govern the use of Parity Technologies Limited&#39;s open source software product (&quot;Parity&quot;). Prior to any use of Parity or any of Parity Technologies Limited&#39;s products (&quot;Parity Technologies&#39; Products&quot;), you (&quot;User&quot; or &quot;you&quot;) 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 (&quot;Parity Technologies&quot; or &quot;we&quot;) is termed the &quot;Parity Technologies Team&quot;.
## 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 (&quot;ETH&quot;) 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, &quot;selfish-mining&quot; 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&#39;s or Parity Technologies&#39; Products&#39; 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&#39; 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)(&quot;Software Licence Terms&quot;).
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&#39; 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&#39; 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&#39; Products are the sole responsibility of the person from which such content originated. All such information is referred to below as &quot;Content&quot;.
You should be aware that Content presented to you through Parity or Parity Technologies&#39; 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&#39; 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&#39; 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&#39; 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&#39; Products, including any intellectual property rights which subsist in Parity and Parity Technologies&#39; 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&#39; 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&#39; 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&#39; 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&#39; 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&#39; 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&#39; Products, grant a security interest in or over your rights to use Parity Technologies&#39; Products, or otherwise transfer any part of your rights to use Parity Technologies&#39; 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&#39; 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&#39; 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&#39; 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&#39; Products;
(B) you must delete or remove Parity or Parity Technologies&#39; 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&#39; Products at the User&#39;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&#39; Products are provided &quot;as is&quot; and &quot;as available.&quot;
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&#39; Products will meet your requirements,
(b) your use of Parity or Parity Technologies&#39; 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&#39; 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&#39; Products will be corrected.
Any material downloaded or otherwise obtained through the use of Parity or Parity Technologies&#39; 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&#39; 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&#39; Products;
(ii) any changes which Parity Technologies may make to Parity Technologies&#39; Products, or for any permanent or temporary cessation in the provision of Parity Technologies&#39; Products (or any features within Parity Technologies&#39; 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&#39; 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&#39; 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&#39; 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&#39; 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&#39; 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&#39; products.
## Other content
Parity Technologies&#39; 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&#39; Product.
You understand and agree that if you use Parity or Parity Technologies&#39; 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&#39; 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&#39; 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&#39; 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&#39; 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&#39; 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&#39;s decision to have three arbitrators; in the case of Respondent, measured from receipt of notification of Claimant&#39;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 &quot;independent&quot; 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, &quot;you&quot; 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&#39; 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).

View File

@ -44,4 +44,7 @@
.accept {
margin: 1.5em 0;
}
.markdown {
}
}

View File

@ -25,6 +25,10 @@ import { statusBlockNumber, statusCollection } from './statusActions';
const log = getLogger(LOG_KEYS.Signer);
let instance = null;
const STATUS_OK = 'ok';
const STATUS_WARN = 'needsAttention';
const STATUS_BAD = 'bad';
export default class Status {
_apiStatus = {};
_status = {};
@ -195,13 +199,16 @@ export default class Status {
const statusPromises = [
this._api.eth.syncing(),
this._api.parity.netPeers()
this._api.parity.netPeers(),
this._fetchHealth()
];
return Promise
.all(statusPromises)
.then(([ syncing, netPeers ]) => {
const status = { netPeers, syncing };
.then(([ syncing, netPeers, health ]) => {
const status = { netPeers, syncing, health };
health.overall = this._overallStatus(health);
if (!isEqual(status, this._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
* unless Parity is restarted. They are thus

View File

@ -18,11 +18,28 @@ import BigNumber from 'bignumber.js';
import { handleActions } from 'redux-actions';
const DEFAULT_NETCHAIN = '(unknown)';
const DEFAULT_STATUS = 'needsAttention';
const initialState = {
blockNumber: new BigNumber(0),
blockTimestamp: new Date(),
clientVersion: '',
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,
netPeers: {
active: new BigNumber(0),

View File

@ -31,7 +31,8 @@ export default class Actionbar extends Component {
title: nodeOrStringProptype(),
buttons: PropTypes.array,
children: PropTypes.node,
className: PropTypes.string
className: PropTypes.string,
health: PropTypes.node
};
static defaultProps = {

View File

@ -0,0 +1,17 @@
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './statusIndicator';

View 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;
}
}

View 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}` } />
);
}
}

View File

@ -52,6 +52,7 @@ export SectionList from './SectionList';
export SelectionList from './SelectionList';
export ShortenedHash from './ShortenedHash';
export SignerIcon from './SignerIcon';
export StatusIndicator from './StatusIndicator';
export Tags from './Tags';
export Title from './Title';
export Tooltips, { Tooltip } from './Tooltips';

View File

@ -43,6 +43,7 @@ class Accounts extends Component {
accountsInfo: PropTypes.object.isRequired,
availability: PropTypes.string.isRequired,
hasAccounts: PropTypes.bool.isRequired,
health: PropTypes.object.isRequired,
setVisibleAccounts: PropTypes.func.isRequired
}
@ -496,12 +497,14 @@ class Accounts extends Component {
function mapStateToProps (state) {
const { accounts, accountsInfo, hasAccounts } = state.personal;
const { availability = 'unknown' } = state.nodeStatus.nodeKind || {};
const { health } = state.nodeStatus;
return {
accounts,
accountsInfo,
availability,
hasAccounts
hasAccounts,
health
};
}

View File

@ -18,7 +18,7 @@ import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import { BlockStatus } from '~/ui';
import { BlockStatus, StatusIndicator } from '~/ui';
import styles from './status.css';
@ -28,11 +28,12 @@ class Status extends Component {
isTest: PropTypes.bool,
netChain: PropTypes.string,
netPeers: PropTypes.object,
health: PropTypes.object,
upgradeStore: PropTypes.object.isRequired
}
render () {
const { clientVersion, isTest, netChain, netPeers } = this.props;
const { clientVersion, isTest, netChain, netPeers, health } = this.props;
return (
<div className={ styles.status }>
@ -44,13 +45,20 @@ class Status extends Component {
{ this.renderUpgradeButton() }
</div>
<div className={ styles.netinfo }>
<BlockStatus />
<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 />
</span>
<div className={ `${styles.network} ${styles[isTest ? 'test' : 'live']}` }>
{ netChain }
</div>
<div className={ styles.peers }>
{ netPeers.connected.toFormat() }/{ netPeers.max.toFormat() } peers
</div>
</div>
</div>
);
@ -102,14 +110,7 @@ class Status extends Component {
);
}
return (
<div>
<FormattedMessage
id='application.status.consensus.unknown'
defaultMessage='Upgrade status is unknown.'
/>
</div>
);
return;
}
renderUpgradeButton () {
@ -136,10 +137,11 @@ class Status extends Component {
}
function mapStateToProps (state) {
const { clientVersion, netPeers, netChain, isTest } = state.nodeStatus;
const { clientVersion, health, netPeers, netChain, isTest } = state.nodeStatus;
return {
clientVersion,
health,
netPeers,
netChain,
isTest

View File

@ -81,6 +81,16 @@
white-space: nowrap;
}
.indicatorTab {
font-size: 1.5rem;
flex: 0;
}
.indicator {
padding: 20px 12px 0;
opacity: 0.8;
}
.first {
margin-left: -24px;
}

View File

@ -21,7 +21,7 @@ import { Link } from 'react-router';
import { Toolbar, ToolbarGroup } from 'material-ui/Toolbar';
import { isEqual } from 'lodash';
import { Tooltip } from '~/ui';
import { Tooltip, StatusIndicator } from '~/ui';
import Tab from './Tab';
import styles from './tabBar.css';
@ -33,6 +33,7 @@ class TabBar extends Component {
static propTypes = {
pending: PropTypes.array,
health: PropTypes.object.isRequired,
views: PropTypes.array.isRequired
};
@ -41,12 +42,29 @@ class TabBar extends Component {
};
render () {
const { health } = this.props;
return (
<Toolbar className={ styles.toolbar }>
<ToolbarGroup className={ styles.first }>
<div />
</ToolbarGroup>
<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() }
<Tooltip
className={ styles.tabbarTooltip }
@ -101,6 +119,7 @@ function mapStateToProps (initState) {
return (state) => {
const { availability = 'unknown' } = state.nodeStatus.nodeKind || {};
const { views } = state.settings;
const { health } = state.nodeStatus;
const viewIds = Object
.keys(views)
@ -114,7 +133,7 @@ function mapStateToProps (initState) {
});
if (isEqual(viewIds, filteredViewIds)) {
return { views: filteredViews };
return { views: filteredViews, health };
}
filteredViewIds = viewIds;
@ -123,7 +142,7 @@ function mapStateToProps (initState) {
id
}));
return { views: filteredViews };
return { views: filteredViews, health };
};
}

View File

@ -37,6 +37,12 @@ function createStore () {
nodeStatus: {
nodeKind: {
'availability': 'personal'
},
health: {
overall: {
status: 'ok',
message: []
}
}
}
};

View File

@ -24,7 +24,7 @@ import { connect } from 'react-redux';
import store from 'store';
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 DappsStore from '~/views/Dapps/dappsStore';
import { Embedded as Signer } from '~/views/Signer';
@ -50,7 +50,8 @@ class ParityBar extends Component {
static propTypes = {
dapp: PropTypes.bool,
externalLink: PropTypes.string,
pending: PropTypes.array
pending: PropTypes.array,
health: PropTypes.object
};
state = {
@ -210,7 +211,7 @@ class ParityBar extends Component {
}
renderBar () {
const { dapp } = this.props;
const { dapp, health } = this.props;
if (!dapp) {
return null;
@ -218,6 +219,13 @@ class ParityBar extends Component {
return (
<div className={ styles.cornercolor }>
<StatusIndicator
type='signal'
id='paritybar.health'
status={ health.overall.status }
title={ health.overall.message }
tooltipPlacement='right'
/>
<Button
className={ styles.iconButton }
icon={
@ -699,9 +707,11 @@ class ParityBar extends Component {
function mapStateToProps (state) {
const { pending } = state.signer;
const { health } = state.nodeStatus;
return {
pending
pending,
health
};
}

View File

@ -37,6 +37,14 @@ function createRedux (state = {}) {
},
signer: {
pending: []
},
nodeStatus: {
health: {
overall: {
status: 'ok',
message: []
}
}
}
}, state)
};

View File

@ -17,7 +17,7 @@
import React from 'react';
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';
@ -65,14 +65,6 @@ const defaultViews = {
value: 'contract'
},
status: {
active: false,
onlyPersonal: true,
icon: <StatusIcon />,
route: '/status',
value: 'status'
},
signer: {
active: true,
fixed: true,

View File

@ -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',
<FormattedMessage

View 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>&nbsp;({ 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);

View File

@ -0,0 +1,17 @@
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './health';

View File

@ -44,7 +44,7 @@
}
.col,
.col3, .col4_5, .col6, .col12 {
.col3, .col4, .col4_5, .col6, .col12 {
float: left;
padding: 0 1em;
box-sizing: border-box;
@ -57,6 +57,13 @@
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 {
width: 37.5%;
width: -webkit-calc(100% / 12 * 4.5);

View File

@ -20,6 +20,7 @@ import { FormattedMessage } from 'react-intl';
import { Page } from '~/ui';
import Debug from './Debug';
import Health from './Health';
import Peers from './Peers';
import NodeStatus from './NodeStatus';
@ -35,6 +36,7 @@ export default () => (
}
>
<div className={ styles.body }>
<Health />
<NodeStatus />
<Peers />
<Debug />

View File

@ -58,3 +58,7 @@
margin: 0.5em 0;
}
}
.status {
font-size: 4rem;
}

View File

@ -20,7 +20,7 @@ import { FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import store from 'store';
import { Button } from '~/ui';
import { Button, StatusIndicator } from '~/ui';
import styles from './syncWarning.css';
@ -38,7 +38,8 @@ export const showSyncWarning = () => {
class SyncWarning extends Component {
static propTypes = {
isSyncing: PropTypes.bool
isOk: PropTypes.bool.isRequired,
health: PropTypes.object.isRequired
};
state = {
@ -47,10 +48,10 @@ class SyncWarning extends Component {
};
render () {
const { isSyncing } = this.props;
const { isOk, health } = this.props;
const { dontShowAgain, show } = this.state;
if (!isSyncing || isSyncing === null || !show) {
if (isOk || !show) {
return null;
}
@ -59,18 +60,19 @@ class SyncWarning extends Component {
<div className={ styles.overlay } />
<div className={ styles.modal }>
<div className={ styles.body }>
<FormattedMessage
id='syncWarning.message.line1'
defaultMessage={ `
Your Parity node is still syncing to the chain.
` }
/>
<FormattedMessage
id='syncWarning.message.line2'
defaultMessage={ `
Some of the shown information might be out-of-date.
` }
/>
<div className={ styles.status }>
<StatusIndicator
type='signal'
id='healthWarning.indicator'
status={ health.overall.status }
/>
</div>
{
health.overall.message.map(message => (
<p key={ message }>{ message }</p>
))
}
<div className={ styles.button }>
<Checkbox
@ -113,14 +115,13 @@ class SyncWarning extends Component {
}
function mapStateToProps (state) {
const { syncing } = state.nodeStatus;
// syncing could be an Object, false, or null
const isSyncing = syncing
? true
: syncing;
const { health } = state.nodeStatus;
const isNotAvailableYet = health.overall.isReady;
const isOk = isNotAvailableYet || health.overall.status === 'ok';
return {
isSyncing
isOk,
health
};
}

View File

@ -26,7 +26,12 @@ function createRedux (syncing = null) {
getState: () => {
return {
nodeStatus: {
syncing
health: {
overall: {
status: syncing ? 'needsAttention' : 'ok',
message: []
}
}
}
};
}

View File

@ -91,7 +91,19 @@ module.exports = {
}
]
},
{
test: /\.md$/,
use: [
{
loader: 'html-loader',
options: {}
},
{
loader: 'markdown-loader',
options: {}
}
]
},
{
test: /\.css$/,
include: [ /src/ ],

View File

@ -89,6 +89,8 @@ pub struct Params {
pub nonce_cap_increment: Option<Uint>,
/// See `CommonParams` docs.
pub remove_dust_contracts : Option<bool>,
/// Wasm support flag
pub wasm: Option<bool>,
}
#[cfg(test)]

View File

@ -67,10 +67,11 @@ pub fn setup_log(config: &Config) -> Result<Arc<RotatingLogger>, String> {
let mut levels = String::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);
// Disable rustls info logging by default.
builder.filter(Some("reqwest"), LogLevelFilter::Warn);
builder.filter(Some("rustls"), LogLevelFilter::Warn);
// Enable info for others.
builder.filter(None, LogLevelFilter::Info);
if let Ok(lvl) = env::var("RUST_LOG") {

View File

@ -71,7 +71,7 @@ pub fn execute(cmd: AccountCmd) -> Result<String, 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);
path.push(spec.data_dir);
RootDiskDirectory::create(path).map_err(|e| format!("Could not open keys directory: {}", e))

View File

@ -29,7 +29,7 @@ use ethcore::error::ImportError;
use ethcore::miner::Miner;
use ethcore::verification::queue::VerifierSettings;
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 helpers::{to_client_config, execute_upgrades};
use dir::Directories;
@ -148,7 +148,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> {
let timer = Instant::now();
// load spec file
let spec = cmd.spec.spec()?;
let spec = cmd.spec.spec(&cmd.dirs.cache)?;
// load genesis 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())?;
let do_import = |bytes| {
@ -320,7 +330,7 @@ fn start_client(
) -> Result<ClientService, String> {
// load spec file
let spec = spec.spec()?;
let spec = spec.spec(&dirs.cache)?;
// load genesis 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> {
let spec = cmd.spec.spec()?;
let spec = cmd.spec.spec(&cmd.dirs.cache)?;
let genesis_hash = spec.genesis_header().hash();
let db_dirs = cmd.dirs.database(genesis_hash, None, spec.data_dir);
let user_defaults_path = db_dirs.user_defaults_path();

View File

@ -78,6 +78,7 @@ disable_periodic = true
jit = false
[misc]
ntp_server = "pool.ntp.org:123"
logging = "own_tx=trace"
log_file = "/var/log/parity.log"
color = true

View File

@ -180,8 +180,10 @@ usage! {
or |c: &Config| otry!(c.rpc).apis.as_ref().map(|vec| vec.join(",")),
flag_jsonrpc_hosts: String = "none",
or |c: &Config| otry!(c.rpc).hosts.as_ref().map(|vec| vec.join(",")),
flag_jsonrpc_threads: Option<usize> = None,
or |c: &Config| otry!(c.rpc).threads.map(Some),
flag_jsonrpc_server_threads: Option<usize> = None,
or |c: &Config| otry!(c.rpc).server_threads.map(Some),
flag_jsonrpc_threads: usize = 0usize,
or |c: &Config| otry!(c.rpc).processing_threads,
// WS
flag_no_ws: bool = false,
@ -250,6 +252,8 @@ usage! {
or |c: &Config| otry!(c.mining).force_sealing.clone(),
flag_reseal_on_txs: String = "own",
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,
or |c: &Config| otry!(c.mining).reseal_min_period.clone(),
flag_reseal_max_period: u64 = 120000u64,
@ -350,6 +354,8 @@ usage! {
or |c: &Config| otry!(c.vm).jit.clone(),
// -- Miscellaneous Options
flag_ntp_server: String = "pool.ntp.org:123",
or |c: &Config| otry!(c.misc).ntp_server.clone(),
flag_logging: Option<String> = None,
or |c: &Config| otry!(c.misc).logging.clone().map(Some),
flag_log_file: Option<String> = None,
@ -466,7 +472,8 @@ struct Rpc {
cors: Option<String>,
apis: Option<Vec<String>>,
hosts: Option<Vec<String>>,
threads: Option<usize>,
server_threads: Option<usize>,
processing_threads: Option<usize>,
}
#[derive(Default, Debug, PartialEq, Deserialize)]
@ -524,6 +531,7 @@ struct Mining {
author: Option<String>,
engine_signer: Option<String>,
force_sealing: Option<bool>,
reseal_on_uncle: Option<bool>,
reseal_on_txs: Option<String>,
reseal_min_period: Option<u64>,
reseal_max_period: Option<u64>,
@ -584,6 +592,7 @@ struct VM {
#[derive(Default, Debug, PartialEq, Deserialize)]
struct Misc {
ntp_server: Option<String>,
logging: Option<String>,
log_file: Option<String>,
color: Option<bool>,
@ -746,7 +755,8 @@ mod tests {
flag_jsonrpc_cors: Some("null".into()),
flag_jsonrpc_apis: "web3,eth,net,parity,traces,rpc,secretstore".into(),
flag_jsonrpc_hosts: "none".into(),
flag_jsonrpc_threads: None,
flag_jsonrpc_server_threads: None,
flag_jsonrpc_threads: 0,
// WS
flag_no_ws: false,
@ -788,6 +798,7 @@ mod tests {
flag_reseal_on_txs: "all".into(),
flag_reseal_min_period: 4000u64,
flag_reseal_max_period: 60000u64,
flag_reseal_on_uncle: false,
flag_work_queue_size: 20usize,
flag_tx_gas_limit: Some("6283184".into()),
flag_tx_time_limit: Some(100u64),
@ -882,6 +893,7 @@ mod tests {
flag_dapps_apis_all: None,
// -- Miscellaneous Options
flag_ntp_server: "pool.ntp.org:123".into(),
flag_version: false,
flag_logging: Some("own_tx=trace".into()),
flag_log_file: Some("/var/log/parity.log".into()),
@ -973,7 +985,8 @@ mod tests {
cors: None,
apis: None,
hosts: None,
threads: None,
server_threads: None,
processing_threads: None,
}),
ipc: Some(Ipc {
disable: None,
@ -1012,6 +1025,7 @@ mod tests {
engine_signer: Some("0xdeadbeefcafe0000000000000000000000000001".into()),
force_sealing: Some(true),
reseal_on_txs: Some("all".into()),
reseal_on_uncle: None,
reseal_min_period: Some(4000),
reseal_max_period: Some(60000),
work_queue_size: None,
@ -1056,6 +1070,7 @@ mod tests {
jit: Some(false),
}),
misc: Some(Misc {
ntp_server: Some("pool.ntp.org:123".into()),
logging: Some("own_tx=trace".into()),
log_file: Some("/var/log/parity.log".into()),
color: Some(true),

View File

@ -176,9 +176,12 @@ API and Console Options:
is additional security against some attack
vectors. Special options: "all", "none",
(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
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})
--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;
all - reseal on all new transactions
(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
incoming transactions. MS is time measured in
milliseconds (default: {flag_reseal_min_period}).
@ -461,6 +467,8 @@ Internal Options:
--can-restart Executable will auto-restart if exiting with 69.
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
format as RUST_LOG. (default: {flag_logging:?})
--log-file FILENAME Specify a filename into which logging should be

View File

@ -34,7 +34,7 @@ use rpc::{IpcConfiguration, HttpConfiguration, WsConfiguration, UiConfiguration}
use rpc_apis::ApiSet;
use parity_rpc::NetworkSettings;
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};
use params::{SpecType, ResealPolicy, AccountsConfig, GasPricerConfig, MinerExtras, Pruning, Switch};
use ethcore_logger::Config as LogConfig;
@ -137,7 +137,7 @@ impl Configuration {
let secretstore_conf = self.secretstore_config()?;
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;
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,
reseal_on_external_tx: reseal.external,
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 {
Some(ref d) => to_u256(d)?,
None => U256::max_value(),
@ -555,6 +556,7 @@ impl Configuration {
fn ui_config(&self) -> UiConfiguration {
UiConfiguration {
enabled: self.ui_enabled(),
ntp_server: self.args.flag_ntp_server.clone(),
interface: self.ui_interface(),
port: self.args.flag_ports_shift + self.args.flag_ui_port,
hosts: self.ui_hosts(),
@ -564,12 +566,18 @@ impl Configuration {
fn dapps_config(&self) -> DappsConfiguration {
DappsConfiguration {
enabled: self.dapps_enabled(),
ntp_server: self.args.flag_ntp_server.clone(),
dapps_path: PathBuf::from(self.directories().dapps),
extra_dapps: if self.args.cmd_dapp {
self.args.arg_path.iter().map(|path| PathBuf::from(path)).collect()
} else {
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 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")?;
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)) {
return Err(format!("Invalid node address format given for a boot node: {}", invalid));
}
@ -824,11 +832,12 @@ impl Configuration {
},
hosts: self.rpc_hosts(),
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),
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)
@ -893,14 +902,20 @@ impl Configuration {
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 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() {
// If base_path is set and db_path is not we default to base path subdir instead of LOCAL.
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.
let base_db_path = if is_using_base_path && self.args.flag_db_path.is_none() {
"$BASE/chains"
} else {
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 dapps_path = replace_home(&data_path, &self.args.flag_dapps_path);
let secretstore_path = replace_home(&data_path, &self.args.flag_secretstore_path);
@ -924,6 +939,7 @@ impl Configuration {
Directories {
keys: keys_path,
base: data_path,
cache: cache_path,
db: db_path,
dapps: dapps_path,
signer: ui_path,
@ -1256,6 +1272,7 @@ mod tests {
support_token_api: true
}, UiConfiguration {
enabled: true,
ntp_server: "pool.ntp.org:123".into(),
interface: "127.0.0.1".into(),
port: 8180,
hosts: Some(vec![]),
@ -1496,6 +1513,7 @@ mod tests {
assert_eq!(conf0.directories().signer, "signer".to_owned());
assert_eq!(conf0.ui_config(), UiConfiguration {
enabled: true,
ntp_server: "pool.ntp.org:123".into(),
interface: "127.0.0.1".into(),
port: 8180,
hosts: Some(vec![]),
@ -1504,14 +1522,17 @@ mod tests {
assert_eq!(conf1.directories().signer, "signer".to_owned());
assert_eq!(conf1.ui_config(), UiConfiguration {
enabled: true,
ntp_server: "pool.ntp.org:123".into(),
interface: "127.0.0.1".into(),
port: 8180,
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!(conf2.directories().signer, "signer".to_owned());
assert_eq!(conf2.ui_config(), UiConfiguration {
enabled: true,
ntp_server: "pool.ntp.org:123".into(),
interface: "127.0.0.1".into(),
port: 3123,
hosts: Some(vec![]),
@ -1520,6 +1541,7 @@ mod tests {
assert_eq!(conf3.directories().signer, "signer".to_owned());
assert_eq!(conf3.ui_config(), UiConfiguration {
enabled: true,
ntp_server: "pool.ntp.org:123".into(),
interface: "test".into(),
port: 8180,
hosts: Some(vec![]),
@ -1554,6 +1576,19 @@ mod tests {
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]
fn test_dev_chain() {
let args = vec!["parity", "--chain", "dev"];

Some files were not shown because too many files have changed in this diff Show More