Compare commits

...

13 Commits

Author SHA1 Message Date
Afri Schoedon
0feb0bb6e7 Backports beta (#7780)
* Bump beta to 1.9.2

* Update ropsten.json (#7776)
2018-02-01 21:09:42 +01:00
GitLab Build Bot
3b5a8d5d69 [ci skip] js-precompiled 20180201-173714 2018-02-01 17:38:09 +00:00
Denis S. Soldatov aka General-Beck
aca9f13d45 snapcraft push beta 2018-02-01 17:31:13 +03:00
GitLab Build Bot
e09bef98fb [ci skip] js-precompiled 20180201-110702 2018-02-01 11:07:58 +00:00
GitLab Build Bot
ceb590a360 [ci skip] js-precompiled 20180201-094935 2018-02-01 09:50:52 +00:00
5chdn
75c0db2b15 Trigger CI 2018-02-01 09:29:47 +01:00
GitLab Build Bot
70b42345c5 [ci skip] js-precompiled 20180201-070128 2018-02-01 07:02:34 +00:00
André Silva
a42d780d02 [Beta] Backports (#7756)
* Filter-out nodes.json (#7716)

* Filter-out nodes.json

* network: sort node table nodes by failure ratio

* network: fix node table tests

* network: fit node failure percentage into buckets of 5%

* network: consider number of attempts in sorting of node table

* network: fix node table grumbles

* Fix client not being dropped on shutdown (#7695)

* parity: wait for client to drop on shutdown

* parity: fix grumbles in shutdown wait

* parity: increase shutdown timeouts

* Wrap --help output to 120 characters (#7626)

* Update Clap dependency and remove workarounds

* WIP

* Remove line breaks in help messages for now

* Multiple values can only be separated by commas (closes #7428)

* Grumbles; refactor repeating code; add constant

* Use a single Wrapper rather than allocate a new one for each call

* Wrap --help to 120 characters rather than 100 characters
2018-01-31 21:45:23 +01:00
GitLab Build Bot
582fa8ce45 [ci skip] js-precompiled 20180131-171157 2018-01-31 17:13:01 +00:00
Jaco Greeff
73be0fb096 [beta] Token filter balances (throttle) (#7742)
* [beta] Token filter balances (throttle)

* Cleanups

* Remove unused uniq

* Update @parity/shared to 2.2.23

* Remove unused code paths
2018-01-31 14:59:53 +01:00
Afri Schoedon
627d1a4971 Bump beta to 1.9.1 (#7751) 2018-01-31 13:25:11 +01:00
Jaco Greeff
a7807106f5 [beta] Explicitly add branch name (#7754)
* [beta] Explicitly add branch name

* Fix cargo update branch to beta
2018-01-31 12:04:04 +01:00
Tomasz Drwięga
33b39f0725 Revert "revert to #7677 #7679" (#7715)
This reverts commit 568dc33a02.
2018-01-29 11:43:30 +01:00
45 changed files with 1021 additions and 1826 deletions

View File

@@ -18,9 +18,9 @@ linux-stable:
stage: build
image: parity/rust:gitlab-ci
only:
- stable
- beta
- tags
- stable
- triggers
script:
- rustup default stable
@@ -36,9 +36,9 @@ linux-stable-debian:
stage: build
image: parity/rust-debian:gitlab-ci
only:
- stable
- beta
- tags
- stable
- triggers
script:
- export LIBSSL="libssl1.1 (>=1.1.0)"
@@ -53,9 +53,9 @@ linux-centos:
stage: build
image: parity/rust-centos:gitlab-ci
only:
- stable
- beta
- tags
- stable
- triggers
script:
- scripts/gitlab-build.sh x86_64-unknown-centos-gnu x86_64-unknown-linux-gnu x86_64 gcc g++
@@ -69,9 +69,9 @@ linux-i686:
stage: build
image: parity/rust-i686:gitlab-ci
only:
- stable
- beta
- tags
- stable
- triggers
script:
- scripts/gitlab-build.sh i686-unknown-linux-gnu i686-unknown-linux-gnu i386 gcc g++
@@ -85,9 +85,9 @@ linux-armv7:
stage: build
image: parity/rust-armv7:gitlab-ci
only:
- stable
- beta
- tags
- stable
- triggers
script:
- scripts/gitlab-build.sh armv7-unknown-linux-gnueabihf armv7-unknown-linux-gnueabihf armhf arm-linux-gnueabihf-gcc arm-linux-gnueabihf-g++
@@ -101,9 +101,9 @@ linux-arm:
stage: build
image: parity/rust-arm:gitlab-ci
only:
- stable
- beta
- tags
- stable
- triggers
script:
- scripts/gitlab-build.sh arm-unknown-linux-gnueabihf arm-unknown-linux-gnueabihf armhf arm-linux-gnueabihf-gcc arm-linux-gnueabihf-g++
@@ -117,9 +117,9 @@ linux-aarch64:
stage: build
image: parity/rust-arm64:gitlab-ci
only:
- stable
- beta
- tags
- stable
- triggers
script:
- scripts/gitlab-build.sh aarch64-unknown-linux-gnu aarch64-unknown-linux-gnu arm64 aarch64-linux-gnu-gcc aarch64-linux-gnu-g++
@@ -143,15 +143,15 @@ linux-snap:
- rust-stable
artifacts:
paths:
- scripts/parity_*_amd64.snap
- snap/parity.zip
name: "stable-x86_64-unknown-snap-gnu_parity"
allow_failure: true
darwin:
stage: build
only:
- stable
- beta
- tags
- stable
- triggers
script:
- scripts/gitlab-build.sh x86_64-apple-darwin x86_64-apple-darwin macos gcc g++
@@ -167,9 +167,9 @@ windows:
untracked: true
stage: build
only:
- stable
- beta
- tags
- stable
- triggers
script:
- sh scripts/gitlab-build.sh x86_64-pc-windows-msvc x86_64-pc-windows-msvc installer "" "" ""
@@ -182,6 +182,8 @@ windows:
docker-build:
stage: build
only:
- stable
- beta
- tags
- triggers
before_script:
@@ -244,8 +246,8 @@ js-release:
stage: js-build
only:
- master
- beta
- stable
- beta
- tags
- triggers
image: parity/rust:gitlab-ci

59
Cargo.lock generated
View File

@@ -25,6 +25,11 @@ name = "ansi_term"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ansi_term"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "app_dirs"
version = "1.1.1"
@@ -163,6 +168,11 @@ name = "bitflags"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bloomable"
version = "0.1.0"
@@ -234,15 +244,14 @@ dependencies = [
[[package]]
name = "clap"
version = "2.26.2"
version = "2.29.1"
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)",
"ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.1 (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)",
"textwrap 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.9.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)",
]
@@ -663,6 +672,8 @@ dependencies = [
"rlp 0.2.1",
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)",
@@ -1903,11 +1914,11 @@ dependencies = [
[[package]]
name = "parity"
version = "1.9.0"
version = "1.9.2"
dependencies = [
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)",
"daemonize 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"dir 0.1.0",
@@ -1951,7 +1962,7 @@ dependencies = [
"parity-rpc 1.9.0",
"parity-rpc-client 1.4.0",
"parity-updater 1.9.0",
"parity-version 1.9.0",
"parity-version 1.9.2",
"parity-whisper 0.1.0",
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"path 0.1.0",
@@ -1966,6 +1977,8 @@ dependencies = [
"serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1997,7 +2010,7 @@ dependencies = [
"parity-hash-fetch 1.9.0",
"parity-reactor 0.1.0",
"parity-ui 1.9.0",
"parity-version 1.9.0",
"parity-version 1.9.2",
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2145,7 +2158,7 @@ dependencies = [
"order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-reactor 0.1.0",
"parity-updater 1.9.0",
"parity-version 1.9.0",
"parity-version 1.9.2",
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2226,7 +2239,7 @@ dependencies = [
[[package]]
name = "parity-ui-old-precompiled"
version = "1.9.0"
source = "git+https://github.com/js-dist-paritytech/parity-beta-1-9-v1.git#bb21e9f134f1d32b878e90e60e83ef84550f032c"
source = "git+https://github.com/js-dist-paritytech/parity-beta-1-9-v1.git#d8d2c5df56b748f20063adda6a67be82451bef86"
dependencies = [
"parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -2234,7 +2247,7 @@ dependencies = [
[[package]]
name = "parity-ui-precompiled"
version = "1.9.0"
source = "git+https://github.com/js-dist-paritytech/parity-beta-1-9-shell.git#630c81d25c268472dbf1ebef60f39852d2805542"
source = "git+https://github.com/js-dist-paritytech/parity-beta-1-9-shell.git#0752597637f5df7baec28082d3e161846880f6bb"
dependencies = [
"parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -2253,7 +2266,7 @@ dependencies = [
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-hash-fetch 1.9.0",
"parity-reactor 0.1.0",
"parity-version 1.9.0",
"parity-version 1.9.2",
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"path 0.1.0",
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2262,7 +2275,7 @@ dependencies = [
[[package]]
name = "parity-version"
version = "1.9.0"
version = "1.9.2"
dependencies = [
"ethcore-bytes 0.1.0",
"rlp 0.2.1",
@@ -2505,7 +2518,7 @@ dependencies = [
name = "pwasm-run-test"
version = "0.1.0"
dependencies = [
"clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-bigint 0.2.1",
"ethcore-logger 1.9.0",
"ethjson 0.1.0",
@@ -2671,7 +2684,7 @@ dependencies = [
[[package]]
name = "rocksdb"
version = "0.4.5"
source = "git+https://github.com/paritytech/rust-rocksdb#7adec2311d31387a832b0ef051472cdef906b480"
source = "git+https://github.com/paritytech/rust-rocksdb#ecf06adf3148ab10f6f7686b724498382ff4f36e"
dependencies = [
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
"local-encoding 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2681,10 +2694,11 @@ dependencies = [
[[package]]
name = "rocksdb-sys"
version = "0.3.0"
source = "git+https://github.com/paritytech/rust-rocksdb#7adec2311d31387a832b0ef051472cdef906b480"
source = "git+https://github.com/paritytech/rust-rocksdb#ecf06adf3148ab10f6f7686b724498382ff4f36e"
dependencies = [
"cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
"local-encoding 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)",
]
@@ -3112,10 +3126,9 @@ dependencies = [
[[package]]
name = "textwrap"
version = "0.8.0"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -3476,7 +3489,7 @@ version = "0.1.0"
source = "git+https://github.com/paritytech/wasm-utils#3d59f7ca0661317bc66894a26b2a5a319fa5d229"
dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3555,6 +3568,7 @@ dependencies = [
"checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45"
"checksum advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a"
"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
"checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455"
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
"checksum app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7d1c0d48a81bbb13043847f957971f4d87c81542d80ece5e84ba3cba4058fd4"
"checksum arrayvec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1c0250693b17316353df525fb088da32a8c18f84eb65d113dde31f5a76ed17b6"
@@ -3573,6 +3587,7 @@ dependencies = [
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4"
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
"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 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d"
@@ -3580,7 +3595,7 @@ dependencies = [
"checksum cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7db2f146208d7e0fbee761b09cd65a7f51ccc38705d4e7262dad4d73b12a76b1"
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
"checksum cid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "34aa7da06f10541fbca6850719cdaa8fa03060a5d2fb33840f149cf8133a00c7"
"checksum clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3451e409013178663435d6f15fdb212f14ee4424a3d74f979d081d0a66b6f1f2"
"checksum clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8f4a2b3bb7ef3c672d7c13d15613211d5a6976b6892c598b0fcb5d40765f19c2"
"checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd"
"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"
@@ -3784,7 +3799,7 @@ dependencies = [
"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
"checksum textwrap 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8e08afc40ae3459e4838f303e465aa50d823df8d7f83ca88108f6d3afe7edd"
"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14"
"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865"
"checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520"

View File

@@ -1,7 +1,7 @@
[package]
description = "Parity Ethereum client"
name = "parity"
version = "1.9.0"
version = "1.9.2"
license = "GPL-3.0"
authors = ["Parity Technologies <admin@parity.io>"]
build = "build.rs"
@@ -12,6 +12,8 @@ env_logger = "0.4"
rustc-hex = "1.0"
docopt = "0.8"
clap = "2"
term_size = "0.3"
textwrap = "0.9"
time = "0.1"
num_cpus = "1.2"
number_prefix = "0.2"

View File

@@ -47,6 +47,8 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embedd
// Content Security Policy headers
headers.set_raw("Content-Security-Policy", String::new()
// Restrict everything to the same origin by default.
+ "default-src 'self';"
// Allow connecting to WS servers and HTTP(S) servers.
// We could be more restrictive and allow only RPC server URL.
+ "connect-src http: https: ws: wss:;"
@@ -64,7 +66,9 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embedd
+ "style-src 'self' 'unsafe-inline' data: blob: https:;"
// Allow fonts from data: and HTTPS.
+ "font-src 'self' data: https:;"
// Allow inline scripts and scripts eval (webpack/jsconsole)
// Disallow objects
+ "object-src 'none';"
// Allow scripts
+ {
let script_src = embeddable_on.as_ref()
.map(|e| e.extra_script_src.iter()
@@ -72,18 +76,16 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embedd
.join(" ")
).unwrap_or_default();
&format!(
"script-src 'self' 'unsafe-inline' 'unsafe-eval' {};",
"script-src 'self' {};",
script_src
)
}
// Same restrictions as script-src with additional
// blob: that is required for camera access (worker)
+ "worker-src 'self' 'unsafe-inline' 'unsafe-eval' https: blob:;"
// Restrict everything else to the same origin.
+ "default-src 'self';"
+ "worker-src 'self' https: blob:;"
// Run in sandbox mode (although it's not fully safe since we allow same-origin and script)
+ "sandbox allow-same-origin allow-forms allow-modals allow-popups allow-presentation allow-scripts;"
// Disallow subitting forms from any dapps
// Disallow submitting forms from any dapps
+ "form-action 'none';"
// Never allow mixed content
+ "block-all-mixed-content;"

View File

@@ -52,6 +52,8 @@
"gasLimit": "0x1000000"
},
"nodes": [
"enode://6332792c4a00e3e4ee0926ed89e0d27ef985424d97b6a45bf0f23e51f0dcb5e66b875777506458aea7af6f9e4ffb69f43f3778ee73c81ed9d34c51c4b16b0b0f@52.232.243.152:30303",
"enode://94c15d1b9e2fe7ce56e458b9a3b672ef11894ddedd0c6f247e0f1d3487f52b66208fb4aeb8179fce6e3a749ea93ed147c37976d67af557508d199d9594c35f09@192.81.208.223:30303",
"enode://20c9ad97c081d63397d7b685a412227a40e23c8bdc6688c6f37e97cfbc22d2b4d1db1510d8f61e6a8866ad7f0e17c02b14182d37ea7c3c8b9c2683aeb6b733a1@52.169.14.227:30303",
"enode://6ce05930c72abc632c58e2e4324f7c7ea478cec0ed4fa2528982cf34483094e9cbc9216e7aa349691242576d552a2a56aaeae426c5303ded677ce455ba1acd9d@13.84.180.240:30303"
],

View File

@@ -44,8 +44,7 @@ use bigint::hash::{H256, H520};
use semantic_version::SemanticVersion;
use parking_lot::{Mutex, RwLock};
use unexpected::{Mismatch, OutOfBounds};
use util::*;
use bytes::Bytes;
use util::Address;
mod finality;
@@ -291,9 +290,11 @@ struct EpochVerifier {
impl super::EpochVerifier<EthereumMachine> for EpochVerifier {
fn verify_light(&self, header: &Header) -> Result<(), Error> {
// Validate the timestamp
verify_timestamp(&*self.step, header_step(header)?)?;
// always check the seal since it's fast.
// nothing heavier to do.
verify_external(header, &self.subchain_validators, &*self.step, |_| {})
verify_external(header, &self.subchain_validators)
}
fn check_finality_proof(&self, proof: &[u8]) -> Option<Vec<H256>> {
@@ -317,7 +318,7 @@ impl super::EpochVerifier<EthereumMachine> for EpochVerifier {
//
// `verify_external` checks that signature is correct and author == signer.
if header.seal().len() != 2 { return None }
otry!(verify_external(header, &self.subchain_validators, &*self.step, |_| {}).ok());
otry!(verify_external(header, &self.subchain_validators).ok());
let newly_finalized = otry!(finality_checker.push_hash(header.hash(), header.author().clone()).ok());
finalized.extend(newly_finalized);
@@ -327,16 +328,6 @@ impl super::EpochVerifier<EthereumMachine> for EpochVerifier {
}
}
// Report misbehavior
#[derive(Debug)]
#[allow(dead_code)]
enum Report {
// Malicious behavior
Malicious(Address, BlockNumber, Bytes),
// benign misbehavior
Benign(Address, BlockNumber),
}
fn header_step(header: &Header) -> Result<usize, ::rlp::DecoderError> {
UntrustedRlp::new(&header.seal().get(0).expect("was either checked with verify_block_basic or is genesis; has 2 fields; qed (Make sure the spec file has a correct genesis seal)")).as_val()
}
@@ -355,34 +346,35 @@ fn is_step_proposer(validators: &ValidatorSet, bh: &H256, step: usize, address:
step_proposer(validators, bh, step) == *address
}
fn verify_external<F: Fn(Report)>(header: &Header, validators: &ValidatorSet, step: &Step, report: F)
-> Result<(), Error>
{
let header_step = header_step(header)?;
fn verify_timestamp(step: &Step, header_step: usize) -> Result<(), BlockError> {
match step.check_future(header_step) {
Err(None) => {
trace!(target: "engine", "verify_block_external: block from the future");
report(Report::Benign(*header.author(), header.number()));
return Err(BlockError::InvalidSeal.into())
trace!(target: "engine", "verify_timestamp: block from the future");
Err(BlockError::InvalidSeal.into())
},
Err(Some(oob)) => {
trace!(target: "engine", "verify_block_external: block too early");
return Err(BlockError::TemporarilyInvalid(oob).into())
// NOTE This error might be returned only in early stage of verification (Stage 1).
// Returning it further won't recover the sync process.
trace!(target: "engine", "verify_timestamp: block too early");
Err(BlockError::TemporarilyInvalid(oob).into())
},
Ok(_) => {
let proposer_signature = header_signature(header)?;
let correct_proposer = validators.get(header.parent_hash(), header_step);
let is_invalid_proposer = *header.author() != correct_proposer ||
!verify_address(&correct_proposer, &proposer_signature, &header.bare_hash())?;
Ok(_) => Ok(()),
}
}
if is_invalid_proposer {
trace!(target: "engine", "verify_block_external: bad proposer for step: {}", header_step);
Err(EngineError::NotProposer(Mismatch { expected: correct_proposer, found: header.author().clone() }))?
} else {
Ok(())
}
}
fn verify_external(header: &Header, validators: &ValidatorSet) -> Result<(), Error> {
let header_step = header_step(header)?;
let proposer_signature = header_signature(header)?;
let correct_proposer = validators.get(header.parent_hash(), header_step);
let is_invalid_proposer = *header.author() != correct_proposer ||
!verify_address(&correct_proposer, &proposer_signature, &header.bare_hash())?;
if is_invalid_proposer {
trace!(target: "engine", "verify_block_external: bad proposer for step: {}", header_step);
Err(EngineError::NotProposer(Mismatch { expected: correct_proposer, found: header.author().clone() }))?
} else {
Ok(())
}
}
@@ -655,26 +647,38 @@ impl Engine<EthereumMachine> for AuthorityRound {
/// Check the number of seal fields.
fn verify_block_basic(&self, header: &Header) -> Result<(), Error> {
if header.number() >= self.validate_score_transition && *header.difficulty() >= U256::from(U128::max_value()) {
Err(From::from(BlockError::DifficultyOutOfBounds(
return Err(From::from(BlockError::DifficultyOutOfBounds(
OutOfBounds { min: None, max: Some(U256::from(U128::max_value())), found: *header.difficulty() }
)))
} else {
Ok(())
)));
}
// TODO [ToDr] Should this go from epoch manager?
// If yes then probably benign reporting needs to be moved further in the verification.
let set_number = header.number();
match verify_timestamp(&*self.step, header_step(header)?) {
Err(BlockError::InvalidSeal) => {
self.validators.report_benign(header.author(), set_number, header.number());
Err(BlockError::InvalidSeal.into())
}
Err(e) => Err(e.into()),
Ok(()) => Ok(()),
}
}
/// Do the step and gas limit validation.
fn verify_block_family(&self, header: &Header, parent: &Header) -> Result<(), Error> {
let step = header_step(header)?;
let parent_step = header_step(parent)?;
// TODO [ToDr] Should this go from epoch manager?
let set_number = header.number();
// Ensure header is from the step after parent.
if step == parent_step
|| (header.number() >= self.validate_step_transition && step <= parent_step) {
trace!(target: "engine", "Multiple blocks proposed for step {}.", parent_step);
self.validators.report_malicious(header.author(), header.number(), header.number(), Default::default());
self.validators.report_malicious(header.author(), set_number, header.number(), Default::default());
Err(EngineError::DoubleVote(header.author().clone()))?;
}
@@ -687,7 +691,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
let skipped_primary = step_proposer(&*self.validators, &parent.hash(), s);
// Do not report this signer.
if skipped_primary != me {
self.validators.report_benign(&skipped_primary, header.number(), header.number());
self.validators.report_benign(&skipped_primary, set_number, header.number());
}
// Stop reporting once validators start repeating.
if !reported.insert(skipped_primary) { break; }
@@ -702,9 +706,8 @@ impl Engine<EthereumMachine> for AuthorityRound {
// fetch correct validator set for current epoch, taking into account
// finality of previous transitions.
let active_set;
let (validators, set_number) = if self.immediate_transitions {
(&*self.validators, header.number())
let validators = if self.immediate_transitions {
&*self.validators
} else {
// get correct validator set for epoch.
let client = match self.client.read().as_ref().and_then(|weak| weak.upgrade()) {
@@ -722,21 +725,12 @@ impl Engine<EthereumMachine> for AuthorityRound {
}
active_set = epoch_manager.validators().clone();
(&active_set as &_, epoch_manager.epoch_transition_number)
};
// always report with "self.validators" so that the report actually gets
// to the contract.
let report = |report| match report {
Report::Benign(address, block_number) =>
self.validators.report_benign(&address, set_number, block_number),
Report::Malicious(address, block_number, proof) =>
self.validators.report_malicious(&address, set_number, block_number, proof),
&active_set as &_
};
// verify signature against fixed list, but reports should go to the
// contract itself.
verify_external(header, validators, &*self.step, report)
verify_external(header, validators)
}
fn genesis_epoch_data(&self, header: &Header, call: &Call) -> Result<Vec<u8>, String> {
@@ -1059,8 +1053,7 @@ mod tests {
assert!(engine.verify_block_family(&header, &parent_header).is_ok());
assert!(engine.verify_block_external(&header).is_ok());
header.set_seal(vec![encode(&5usize).into_vec(), encode(&(&*signature as &[u8])).into_vec()]);
assert!(engine.verify_block_family(&header, &parent_header).is_ok());
assert!(engine.verify_block_external(&header).is_err());
assert!(engine.verify_block_basic(&header).is_err());
}
#[test]
@@ -1200,3 +1193,4 @@ mod tests {
AuthorityRound::new(params, machine).unwrap();
}
}

View File

@@ -192,7 +192,7 @@ mod tests {
header.set_number(2);
header.set_parent_hash(client.chain_info().best_block_hash);
// `reportBenign` when the designated proposer releases block from the future (bad clock).
assert!(client.engine().verify_block_external(&header).is_err());
assert!(client.engine().verify_block_basic(&header).is_err());
// Seal a block.
client.engine().step();
assert_eq!(client.chain_info().best_block_number, 1);

View File

@@ -1406,7 +1406,7 @@ mod tests {
}
#[test]
fn should_not_trace_delegatecall() {
fn should_trace_delegatecall_properly() {
init_log();
let mut state = get_temp_state();
@@ -1426,7 +1426,7 @@ mod tests {
}.sign(&secret(), None);
state.init_code(&0xa.into(), FromHex::from_hex("6000600060006000600b618000f4").unwrap()).unwrap();
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()).unwrap();
state.init_code(&0xb.into(), FromHex::from_hex("60056000526001601ff3").unwrap()).unwrap();
let result = state.apply(&info, &machine, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
@@ -1441,23 +1441,23 @@ mod tests {
call_type: CallType::Call,
}),
result: trace::Res::Call(trace::CallResult {
gas_used: U256::from(721), // in post-eip150
gas_used: U256::from(736), // in post-eip150
output: vec![]
}),
}, FlatTrace {
trace_address: vec![0].into_iter().collect(),
subtraces: 0,
action: trace::Action::Call(trace::Call {
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
to: 0xa.into(),
from: 0xa.into(),
to: 0xb.into(),
value: 0.into(),
gas: 32768.into(),
input: vec![],
call_type: CallType::DelegateCall,
}),
result: trace::Res::Call(trace::CallResult {
gas_used: 3.into(),
output: vec![],
gas_used: 18.into(),
output: vec![5],
}),
}];

View File

@@ -74,13 +74,23 @@ pub struct Call {
impl From<ActionParams> for Call {
fn from(p: ActionParams) -> Self {
Call {
from: p.sender,
to: p.address,
value: p.value.value(),
gas: p.gas,
input: p.data.unwrap_or_else(Vec::new),
call_type: p.call_type,
match p.call_type {
CallType::DelegateCall => Call {
from: p.address,
to: p.code_address,
value: p.value.value(),
gas: p.gas,
input: p.data.unwrap_or_else(Vec::new),
call_type: p.call_type,
},
_ => Call {
from: p.sender,
to: p.address,
value: p.value.value(),
gas: p.gas,
input: p.data.unwrap_or_else(Vec::new),
call_type: p.call_type,
},
}
}
}

View File

@@ -4,8 +4,9 @@ set -e
# variables
PVER="1-9"
PTYPE="v1"
TRACK="beta"
UTCDATE=`date -u "+%Y%m%d-%H%M%S"`
PRE_REPO="js-dist-paritytech/parity-${CI_BUILD_REF_NAME}-${PVER}-${PTYPE}.git"
PRE_REPO="js-dist-paritytech/parity-${TRACK}-${PVER}-${PTYPE}.git"
PRE_REPO_TOKEN="https://${GITHUB_JS_PRECOMPILED}:@github.com/${PRE_REPO}"
BASEDIR=`dirname $0`

View File

@@ -1 +1 @@
// test script 24
// test script 25

View File

@@ -306,7 +306,7 @@ export function fetchTokensBalances (updates, skipNotifications = false) {
const tokenIdsToFetch = Object.values(balances)
.reduce((tokenIds, balance) => {
const nextTokenIds = Object.keys(balance)
.filter((tokenId) => balance[tokenId].gt(0));
.filter((tokenId) => balance[tokenId] && balance[tokenId].gt(0));
return tokenIds.concat(nextTokenIds);
}, []);
@@ -328,7 +328,7 @@ export function fetchTokensBalances (updates, skipNotifications = false) {
dispatch(setBalances(balances, skipNotifications));
})
.catch((error) => {
console.warn('balances::fetchTokensBalances', error);
console.warn('v1: balances::fetchTokensBalances', error);
});
};
}

View File

@@ -105,7 +105,7 @@ export function loadTokens (options = {}) {
}
export function loadTokensBasics (tokenIndexes, options) {
const limit = 64;
const limit = 128;
return (dispatch, getState) => {
const { api } = getState();
@@ -154,7 +154,7 @@ export function loadTokensBasics (tokenIndexes, options) {
export function fetchTokens (_tokenIndexes) {
const tokenIndexes = uniq(_tokenIndexes || []);
const tokenChunks = chunk(tokenIndexes, 64);
const tokenChunks = chunk(tokenIndexes, 128);
return (dispatch, getState) => {
const { tokenReg } = Contracts.get();

View File

@@ -65,15 +65,15 @@ export default function (api, browserHistory, forEmbed = false) {
.then(() => console.log('v1: started Status Provider'))
.then(() => console.log('v1: starting Personal Provider...'))
.then(() => PersonalProvider.start())
.then(() => withTimeoutForLight('personal', PersonalProvider.start(), store))
.then(() => console.log('v1: started Personal Provider'))
.then(() => console.log('v1: starting Balances Provider...'))
.then(() => BalancesProvider.start())
.then(() => withTimeoutForLight('balances', BalancesProvider.start(), store))
.then(() => console.log('v1: started Balances Provider'))
.then(() => console.log('v1: starting Tokens Provider...'))
.then(() => TokensProvider.start())
.then(() => withTimeoutForLight('tokens', TokensProvider.start(), store))
.then(() => console.log('v1: started Tokens Provider'));
};
@@ -97,3 +97,39 @@ export default function (api, browserHistory, forEmbed = false) {
return store;
}
function withTimeoutForLight (id, promise, store) {
const { nodeKind } = store.getState().nodeStatus;
const isLightNode = nodeKind.capability !== 'full';
if (!isLightNode) {
// make sure that no values are passed
return promise.then(() => {});
}
return new Promise((resolve, reject) => {
let isResolved = false;
const doResolve = () => {
if (!isResolved) {
isResolved = true;
resolve();
}
};
const timeout = setTimeout(() => {
console.warn(`Resolving ${id} by timeout.`);
doResolve();
}, 1000);
promise
.then(() => {
clearTimeout(timeout);
doResolve();
})
.catch(err => {
clearTimeout(timeout);
if (!isResolved) {
reject(err);
}
});
});
}

View File

@@ -14,7 +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 { range } from 'lodash';
import { chunk, range } from 'lodash';
import BigNumber from 'bignumber.js';
import { hashToImageUrl } from '~/redux/util';
@@ -58,13 +58,11 @@ export function fetchTokensBasics (api, tokenReg, start = 0, limit = 100) {
return decodeArray(api, 'address[]', result);
})
.then((tokenAddresses) => {
return tokenAddresses.map((tokenAddress, index) => {
return tokenAddresses.map((address, index) => {
const tokenIndex = start + index;
return {
address: /^0x0*$/.test(tokenAddress)
? ''
: tokenAddress,
address,
id: getTokenId(tokenIndex),
index: tokenIndex,
fetched: false
@@ -80,12 +78,17 @@ export function fetchTokensBasics (api, tokenReg, start = 0, limit = 100) {
return tokens.map((token) => {
if (balances[token.id] && balances[token.id].gt(0)) {
token.address = '';
token.address = null;
}
return token;
});
});
})
.then((tokens) => {
return tokens.filter(({ address }) => {
return address && !/^0x0*$/.test(address);
});
});
}
@@ -195,19 +198,22 @@ export function fetchAccountsBalances (api, tokens, updates) {
});
const tokenPromise = Object.keys(tokenUpdates)
.reduce((tokenPromise, accountAddress) => {
.reduce((promises, accountAddress) => {
const tokenIds = tokenUpdates[accountAddress];
const updateTokens = tokens
.filter((t) => tokenIds.includes(t.id));
return tokenPromise
.then(() => fetchTokensBalances(api, updateTokens, [ accountAddress ]))
.then((balances) => {
tokensBalances[accountAddress] = balances[accountAddress];
});
}, Promise.resolve());
promises.push(
fetchTokensBalances(api, updateTokens, [ accountAddress ])
.then((balances) => {
tokensBalances[accountAddress] = balances[accountAddress];
})
);
return Promise.all([ ethPromise, tokenPromise ])
return promises;
}, []);
return Promise.all([ ethPromise, Promise.all(tokenPromise) ])
.then(() => {
const balances = Object.assign({}, tokensBalances);
@@ -243,29 +249,24 @@ function fetchEthBalances (api, accountAddresses) {
});
}
function fetchTokensBalances (api, tokens, accountAddresses) {
const tokenAddresses = tokens.map((t) => t.address);
const tokensBalancesCallData = encode(
api,
[ 'address[]', 'address[]' ],
[ accountAddresses, tokenAddresses ]
);
function fetchTokensBalances (api, _tokens, accountAddresses) {
const promises = chunk(_tokens, 128).map((tokens) => {
const data = tokensBalancesBytecode + encode(
api,
[ 'address[]', 'address[]' ],
[ accountAddresses, tokens.map(({ address }) => address) ]
);
return api.eth
.call({ data: tokensBalancesBytecode + tokensBalancesCallData })
.then((result) => {
const rawBalances = decodeArray(api, 'uint[]', result);
return api.eth.call({ data }).then((result) => {
const balances = {};
const rawBalances = decodeArray(api, 'uint[]', result);
accountAddresses.forEach((accountAddress, accountIndex) => {
const preIndex = accountIndex * tokens.length;
const balance = {};
const preIndex = accountIndex * tokenAddresses.length;
tokenAddresses.forEach((tokenAddress, tokenIndex) => {
const index = preIndex + tokenIndex;
const token = tokens[tokenIndex];
balance[token.id] = rawBalances[index];
tokens.forEach((token, tokenIndex) => {
balance[token.id] = rawBalances[preIndex + tokenIndex];
});
balances[accountAddress] = balance;
@@ -273,6 +274,31 @@ function fetchTokensBalances (api, tokens, accountAddresses) {
return balances;
});
});
return Promise.all(promises).then((results) => {
return results.reduce((combined, result) => {
Object
.keys(result)
.forEach((address) => {
if (!combined[address]) {
combined[address] = {};
}
Object
.keys(result[address])
.forEach((token) => {
const value = result[address][token];
if (value && value.gt(0)) {
combined[address][token] = result[address][token];
}
});
});
return combined;
}, {});
});
}
function getTokenId (...args) {

1573
js/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -146,7 +146,7 @@
"@parity/plugin-signer-default": "parity-js/plugin-signer-default#9a47bded9d6d70b69bb2f719732bd6f7854d1842",
"@parity/plugin-signer-hardware": "parity-js/plugin-signer-hardware#4320d818a053d4efae890b74a7476e4c8dc6ba10",
"@parity/plugin-signer-qr": "parity-js/plugin-signer-qr#2d1fafad347ba53eaf58c14265d4d07631d6a45c",
"@parity/shared": "2.2.21",
"@parity/shared": "2.2.23",
"@parity/ui": "3.0.22",
"keythereum": "1.0.2",
"lodash.flatten": "4.4.0",
@@ -170,7 +170,6 @@
"redux": "3.7.2",
"semantic-ui-react": "0.77.0",
"solc": "ngotchac/solc-js",
"store": "1.3.20",
"web3": "1.0.0-beta.26"
"store": "1.3.20"
}
}

View File

@@ -4,7 +4,7 @@ set -e
# variables
PVER="1-9"
UTCDATE=`date -u "+%Y%m%d-%H%M%S"`
BRANCH=$CI_BUILD_REF_NAME
BRANCH="beta"
GIT_PARITY="https://${GITHUB_JS_PRECOMPILED}:@github.com/paritytech/parity.git"
echo "*** [cargo] Setting up GitHub config for parity"

View File

@@ -4,8 +4,9 @@ set -e
# variables
PVER="1-9"
PTYPE="shell"
TRACK="beta"
UTCDATE=`date -u "+%Y%m%d-%H%M%S"`
PRE_REPO="js-dist-paritytech/parity-${CI_BUILD_REF_NAME}-${PVER}-${PTYPE}.git"
PRE_REPO="js-dist-paritytech/parity-${TRACK}-${PVER}-${PTYPE}.git"
PRE_REPO_TOKEN="https://${GITHUB_JS_PRECOMPILED}:@github.com/${PRE_REPO}"
BASEDIR=`dirname $0`

View File

@@ -1 +1 @@
// test script 30
// test script 31

View File

@@ -26,11 +26,14 @@
.list {
margin: 0 !important;
padding: 1em 1em !important;
background-color: #f5f5f5;
background-color: white;
}
.isDefault {
background-color: white;
.accountsList {
background-color: #f5f5f5;
height: 300px;
overflow-y: auto;
}
.hasOtherAccounts {

View File

@@ -68,14 +68,14 @@ class DefaultAccount extends Component {
}
content={
<div>
<List relaxed='very' selection className={ [styles.list, styles.isDefault, allAccounts.length > 1 && styles.hasOtherAccounts].join(' ') }>
<List relaxed='very' selection className={ [styles.list, allAccounts.length > 1 && styles.hasOtherAccounts].join(' ') }>
<AccountItem
isDefault
account={ defaultAccount }
/>
</List>
{allAccounts.length > 1 &&
<List relaxed='very' selection className={ styles.list } divided>
<List relaxed='very' selection className={ [styles.list, styles.accountsList].join(' ') } divided>
{allAccounts
.filter(({ address }) => address !== defaultAddress)
.map(account => (

View File

@@ -16,7 +16,6 @@
import Api from '@parity/api';
import qs from 'query-string';
import Web3 from 'web3';
function initProvider () {
const path = window.location.pathname.split('/');
@@ -48,24 +47,9 @@ function initProvider () {
}
function initWeb3 (ethereum) {
// FIXME: Use standard provider for web3
const provider = new Api.Provider.SendAsync(ethereum);
const web3 = new Web3(provider);
const currentProvider = new Api.Provider.SendAsync(ethereum);
if (!web3.currentProvider) {
web3.currentProvider = provider;
}
// set default account
web3.eth.getAccounts((error, accounts) => {
if (error || !accounts || !accounts[0]) {
return;
}
web3.eth.defaultAccount = accounts[0];
});
window.web3 = web3;
window.web3 = { currentProvider };
}
function initParity (ethereum) {

View File

@@ -462,7 +462,7 @@
<key>OVERWRITE_PERMISSIONS</key>
<false/>
<key>VERSION</key>
<string>1.9.0</string>
<string>1.9.2</string>
</dict>
<key>UUID</key>
<string>2DCD5B81-7BAF-4DA1-9251-6274B089FD36</string>

View File

@@ -9,8 +9,8 @@
!define COMPANYNAME "Parity Technologies"
!define DESCRIPTION "Fast, light, robust Ethereum implementation"
!define VERSIONMAJOR 1
!define VERSIONMINOR 10
!define VERSIONBUILD 0
!define VERSIONMINOR 9
!define VERSIONBUILD 2
!define ARGS ""
!define FIRST_START_ARGS "--mode=passive ui"

View File

@@ -257,12 +257,7 @@ usage! {
ARG arg_mode: (String) = "last", or |c: &Config| otry!(c.parity).mode.clone(),
"--mode=[MODE]",
"Set the operating mode. MODE can be one of:
last - Uses the last-used mode, active if none.
active - Parity continuously syncs the chain.
passive - Parity syncs initially, then sleeps and wakes regularly to resync.
dark - Parity syncs only when the RPC is active.
offline - Parity doesn't sync.",
"Set the operating mode. MODE can be one of: last - Uses the last-used mode, active if none; active - Parity continuously syncs the chain; passive - Parity syncs initially, then sleeps and wakes regularly to resync; dark - Parity syncs only when the RPC is active; offline - Parity doesn't sync.",
ARG arg_mode_timeout: (u64) = 300u64, or |c: &Config| otry!(c.parity).mode_timeout.clone(),
"--mode-timeout=[SECS]",
@@ -274,19 +269,11 @@ usage! {
ARG arg_auto_update: (String) = "critical", or |c: &Config| otry!(c.parity).auto_update.clone(),
"--auto-update=[SET]",
"Set a releases set to automatically update and install.
all - All updates in the our release track.
critical - Only consensus/security updates.
none - No updates will be auto-installed.",
"Set a releases set to automatically update and install. SET can be one of: all - All updates in the our release track; critical - Only consensus/security updates; none - No updates will be auto-installed.",
ARG arg_release_track: (String) = "current", or |c: &Config| otry!(c.parity).release_track.clone(),
"--release-track=[TRACK]",
"Set which release track we should use for updates.
stable - Stable releases.
beta - Beta releases.
nightly - Nightly releases (unstable).
testing - Testing releases (do not use).
current - Whatever track this executable was released on",
"Set which release track we should use for updates. TRACK can be one of: stable - Stable releases; beta - Beta releases; nightly - Nightly releases (unstable); testing - Testing releases (do not use); current - Whatever track this executable was released on.",
ARG arg_chain: (String) = "foundation", or |c: &Config| otry!(c.parity).chain.clone(),
"--chain=[CHAIN]",
@@ -311,8 +298,7 @@ usage! {
["Convenience options"]
FLAG flag_unsafe_expose: (bool) = false, or |c: &Config| otry!(c.misc).unsafe_expose,
"--unsafe-expose",
"All servers will listen on external interfaces and will be remotely accessible. It's equivalent with setting the following: --{{ws,jsonrpc,ui,ipfs,secret_store,stratum}}-interface=all --*-hosts=all
This option is UNSAFE and should be used with great care!",
"All servers will listen on external interfaces and will be remotely accessible. It's equivalent with setting the following: --{{ws,jsonrpc,ui,ipfs,secret_store,stratum}}-interface=all --*-hosts=all This option is UNSAFE and should be used with great care!",
ARG arg_config: (String) = "$BASE/config.toml", or |_| None,
"-c, --config=[CONFIG]",
@@ -498,7 +484,7 @@ usage! {
ARG arg_ws_hosts: (String) = "none", or |c: &Config| otry!(c.websockets).hosts.as_ref().map(|vec| vec.join(",")),
"--ws-hosts=[HOSTS]",
"List of allowed Host header values. This option will validate the Host header sent by the browser, it is additional security against some attack vectors. Special options: \"all\", \"none\",.",
"List of allowed Host header values. This option will validate the Host header sent by the browser, it is additional security against some attack vectors. Special options: \"all\", \"none\".",
["API and console options IPC"]
FLAG flag_no_ipc: (bool) = false, or |c: &Config| otry!(c.ipc).disable.clone(),
@@ -582,7 +568,7 @@ usage! {
ARG arg_secretstore_path: (String) = "$BASE/secretstore", or |c: &Config| otry!(c.secretstore).path.clone(),
"--secretstore-path=[PATH]",
"Specify directory where Secret Store should save its data..",
"Specify directory where Secret Store should save its data.",
ARG arg_secretstore_secret: (Option<String>) = None, or |c: &Config| otry!(c.secretstore).self_secret.clone(),
"--secretstore-secret=[SECRET]",
@@ -671,7 +657,7 @@ usage! {
ARG arg_tx_queue_gas: (String) = "off", or |c: &Config| otry!(c.mining).tx_queue_gas.clone(),
"--tx-queue-gas=[LIMIT]",
"Maximum amount of total gas for external transactions in the queue. LIMIT can be either an amount of gas or 'auto' or 'off'. 'auto' sets the limit to be 20x the current block gas limit..",
"Maximum amount of total gas for external transactions in the queue. LIMIT can be either an amount of gas or 'auto' or 'off'. 'auto' sets the limit to be 20x the current block gas limit.",
ARG arg_tx_queue_strategy: (String) = "gas_price", or |c: &Config| otry!(c.mining).tx_queue_strategy.clone(),
"--tx-queue-strategy=[S]",
@@ -778,7 +764,7 @@ usage! {
ARG arg_pruning_history: (u64) = 64u64, or |c: &Config| otry!(c.footprint).pruning_history.clone(),
"--pruning-history=[NUM]",
"Set a minimum number of recent states to keep when pruning is active..",
"Set a minimum number of recent states to keep when pruning is active.",
ARG arg_pruning_memory: (usize) = 32usize, or |c: &Config| otry!(c.footprint).pruning_memory.clone(),
"--pruning-memory=[MB]",
@@ -1322,12 +1308,15 @@ mod tests {
let args = Args::parse(&["parity", "--secretstore-nodes", "abc@127.0.0.1:3333,cde@10.10.10.10:4444"]).unwrap();
assert_eq!(args.arg_secretstore_nodes, "abc@127.0.0.1:3333,cde@10.10.10.10:4444");
// Arguments with a single value shouldn't accept multiple values
let args = Args::parse(&["parity", "--auto-update", "critical", "all"]);
assert!(args.is_err());
let args = Args::parse(&["parity", "--password", "~/.safe/1", "~/.safe/2"]).unwrap();
let args = Args::parse(&["parity", "--password", "~/.safe/1", "--password", "~/.safe/2", "--ui-port", "8123", "ui"]).unwrap();
assert_eq!(args.arg_password, vec!["~/.safe/1".to_owned(), "~/.safe/2".to_owned()]);
assert_eq!(args.arg_ui_port, 8123);
assert_eq!(args.cmd_ui, true);
let args = Args::parse(&["parity", "--password", "~/.safe/1,~/.safe/2", "--ui-port", "8123", "ui"]).unwrap();
assert_eq!(args.arg_password, vec!["~/.safe/1".to_owned(), "~/.safe/2".to_owned()]);
assert_eq!(args.arg_ui_port, 8123);
assert_eq!(args.cmd_ui, true);
}
#[test]

View File

@@ -150,14 +150,20 @@ macro_rules! usage {
}
) => {
use toml;
use std::{fs, io, process};
use std::{fs, io, process, cmp};
use std::io::{Read, Write};
use parity_version::version;
use clap::{Arg, App, SubCommand, AppSettings, ArgMatches as ClapArgMatches, Error as ClapError, ErrorKind as ClapErrorKind};
use clap::{Arg, App, SubCommand, AppSettings, ArgSettings, Error as ClapError, ErrorKind as ClapErrorKind};
use dir::helpers::replace_home;
use std::ffi::OsStr;
use std::collections::HashMap;
extern crate textwrap;
extern crate term_size;
use self::textwrap::{Wrapper};
const MAX_TERM_WIDTH: usize = 120;
#[cfg(test)]
use regex::Regex;
@@ -365,11 +371,23 @@ macro_rules! usage {
#[allow(unused_mut)] // subc_subc_exist may be assigned true by the macro
#[allow(unused_assignments)] // Rust issue #22630
pub fn print_help() -> String {
const TAB: &str = " ";
const TAB_TAB: &str = " ";
let term_width = match term_size::dimensions() {
None => MAX_TERM_WIDTH,
Some((w, _)) => {
cmp::min(w, MAX_TERM_WIDTH)
}
};
let mut help : String = include_str!("./usage_header.txt").to_owned();
help.push_str("\n\n");
help.push_str("\n");
// Subcommands
let mut subcommands_wrapper = Wrapper::new(term_width).subsequent_indent(TAB);
help.push_str("parity [options]\n");
$(
{
@@ -386,11 +404,14 @@ macro_rules! usage {
)*
];
if subc_subc_usages.is_empty() {
help.push_str(&format!("parity [options] {} {}\n", underscore_to_hyphen!(&stringify!($subc)[4..]), underscore_to_hyphen!(&stringify!($subc_subc)[stringify!($subc).len()+1..])));
} else {
help.push_str(&format!("parity [options] {} {} {}\n", underscore_to_hyphen!(&stringify!($subc)[4..]), underscore_to_hyphen!(&stringify!($subc_subc)[stringify!($subc).len()+1..]), subc_subc_usages.join(" ")));
}
help.push_str(&subcommands_wrapper.fill(
format!(
"parity [options] {} {} {}\n",
underscore_to_hyphen!(&stringify!($subc)[4..]),
underscore_to_hyphen!(&stringify!($subc_subc)[stringify!($subc).len()+1..]),
subc_subc_usages.join(" ")
).as_ref())
);
)*
// Print the subcommand on its own only if it has no subsubcommands
@@ -404,22 +425,30 @@ macro_rules! usage {
)*
];
if subc_usages.is_empty() {
help.push_str(&format!("parity [options] {}\n", underscore_to_hyphen!(&stringify!($subc)[4..])));
} else {
help.push_str(&format!("parity [options] {} {}\n", underscore_to_hyphen!(&stringify!($subc)[4..]), subc_usages.join(" ")));
}
help.push_str(&subcommands_wrapper.fill(
format!(
"parity [options] {} {}\n",
underscore_to_hyphen!(&stringify!($subc)[4..]),
subc_usages.join(" ")
).as_ref())
);
}
}
)*
help.push_str("\n");
// Arguments and flags
let args_wrapper = Wrapper::new(term_width).initial_indent(TAB_TAB).subsequent_indent(TAB_TAB);
$(
help.push_str("\n");
help.push_str($group_name); help.push_str(":\n");
$(
help.push_str(&format!("\t{}\n\t\t{}\n", $flag_usage, $flag_help));
help.push_str(&format!("{}{}\n{}\n",
TAB, $flag_usage,
args_wrapper.fill($flag_help)
));
help.push_str("\n");
)*
$(
@@ -429,10 +458,24 @@ macro_rules! usage {
if_option_vec!(
$($arg_type_tt)+,
THEN {
help.push_str(&format!("\t{}\n\t\t{} (default: {:?})\n", $arg_usage, $arg_help, {let x : inner_option_type!($($arg_type_tt)+)> = $arg_default; x}))
help.push_str(&format!("{}{}\n{}\n",
TAB, $arg_usage,
args_wrapper.fill(format!(
"{} (default: {:?})",
$arg_help,
{let x : inner_option_type!($($arg_type_tt)+)> = $arg_default; x}
).as_ref())
))
}
ELSE {
help.push_str(&format!("\t{}\n\t\t{}{}\n", $arg_usage, $arg_help, $arg_default.map(|x: inner_option_type!($($arg_type_tt)+)| format!(" (default: {})",x)).unwrap_or("".to_owned())))
help.push_str(&format!("{}{}\n{}\n",
TAB, $arg_usage,
args_wrapper.fill(format!(
"{}{}",
$arg_help,
$arg_default.map(|x: inner_option_type!($($arg_type_tt)+)| format!(" (default: {})",x)).unwrap_or("".to_owned())
).as_ref())
))
}
)
}
@@ -440,14 +483,27 @@ macro_rules! usage {
if_vec!(
$($arg_type_tt)+,
THEN {
help.push_str(&format!("\t{}\n\t\t{} (default: {:?})\n", $arg_usage, $arg_help, {let x : $($arg_type_tt)+ = $arg_default; x}))
help.push_str(&format!("{}{}\n{}\n", TAB, $arg_usage,
args_wrapper.fill(format!(
"{} (default: {:?})",
$arg_help,
{let x : $($arg_type_tt)+ = $arg_default; x}
).as_ref())
))
}
ELSE {
help.push_str(&format!("\t{}\n\t\t{} (default: {})\n", $arg_usage, $arg_help, $arg_default))
help.push_str(&format!("{}{}\n{}\n", TAB, $arg_usage,
args_wrapper.fill(format!(
"{} (default: {})",
$arg_help,
$arg_default
).as_ref())
))
}
)
}
);
help.push_str("\n");
)*
)*
@@ -503,36 +559,6 @@ macro_rules! usage {
args
}
pub fn hydrate_with_globals(self: &mut Self, matches: &ClapArgMatches) -> Result<(), ClapError> {
$(
$(
self.$flag = self.$flag || matches.is_present(stringify!($flag));
)*
$(
if let some @ Some(_) = return_if_parse_error!(if_option!(
$($arg_type_tt)+,
THEN {
if_option_vec!(
$($arg_type_tt)+,
THEN { values_t!(matches, stringify!($arg), inner_option_vec_type!($($arg_type_tt)+)) }
ELSE { value_t!(matches, stringify!($arg), inner_option_type!($($arg_type_tt)+)) }
)
}
ELSE {
if_vec!(
$($arg_type_tt)+,
THEN { values_t!(matches, stringify!($arg), inner_vec_type!($($arg_type_tt)+)) }
ELSE { value_t!(matches, stringify!($arg), $($arg_type_tt)+) }
)
}
)) {
self.$arg = some;
}
)*
)*
Ok(())
}
#[allow(unused_variables)] // the submatches of arg-less subcommands aren't used
pub fn parse<S: AsRef<str>>(command: &[S]) -> Result<Self, ClapError> {
@@ -582,21 +608,31 @@ macro_rules! usage {
let matches = App::new("Parity")
.global_setting(AppSettings::VersionlessSubcommands)
.global_setting(AppSettings::DisableHelpSubcommand)
.max_term_width(MAX_TERM_WIDTH)
.help(Args::print_help().as_ref())
.args(&usages.iter().map(|u| Arg::from_usage(u).use_delimiter(false).allow_hyphen_values(true)).collect::<Vec<Arg>>())
.args(&usages.iter().map(|u| {
let mut arg = Arg::from_usage(u)
.allow_hyphen_values(true) // Allow for example --allow-ips -10.0.0.0/8
.global(true) // Argument doesn't have to come before the first subcommand
.hidden(true); // Hide global arguments from the (subcommand) help messages generated by Clap
if arg.is_set(ArgSettings::Multiple) {
arg = arg.require_delimiter(true); // Multiple values can only be separated by commas, not spaces (#7428)
}
arg
}).collect::<Vec<Arg>>())
$(
.subcommand(
SubCommand::with_name(&underscore_to_hyphen!(&stringify!($subc)[4..]))
.about($subc_help)
.args(&subc_usages.get(stringify!($subc)).unwrap().iter().map(|u| Arg::from_usage(u).use_delimiter(false).allow_hyphen_values(true)).collect::<Vec<Arg>>())
.args(&usages.iter().map(|u| Arg::from_usage(u).use_delimiter(false).allow_hyphen_values(true)).collect::<Vec<Arg>>()) // accept global arguments at this position
$(
.setting(AppSettings::SubcommandRequired) // prevent from running `parity account`
.subcommand(
SubCommand::with_name(&underscore_to_hyphen!(&stringify!($subc_subc)[stringify!($subc).len()+1..]))
.about($subc_subc_help)
.args(&subc_usages.get(stringify!($subc_subc)).unwrap().iter().map(|u| Arg::from_usage(u).use_delimiter(false).allow_hyphen_values(true)).collect::<Vec<Arg>>())
.args(&usages.iter().map(|u| Arg::from_usage(u).use_delimiter(false).allow_hyphen_values(true)).collect::<Vec<Arg>>()) // accept global arguments at this position
)
)*
)
@@ -605,15 +641,39 @@ macro_rules! usage {
let mut raw_args : RawArgs = Default::default();
raw_args.hydrate_with_globals(&matches)?;
// Globals
$(
$(
raw_args.$flag = raw_args.$flag || matches.is_present(stringify!($flag));
)*
$(
if let some @ Some(_) = return_if_parse_error!(if_option!(
$($arg_type_tt)+,
THEN {
if_option_vec!(
$($arg_type_tt)+,
THEN { values_t!(matches, stringify!($arg), inner_option_vec_type!($($arg_type_tt)+)) }
ELSE { value_t!(matches, stringify!($arg), inner_option_type!($($arg_type_tt)+)) }
)
}
ELSE {
if_vec!(
$($arg_type_tt)+,
THEN { values_t!(matches, stringify!($arg), inner_vec_type!($($arg_type_tt)+)) }
ELSE { value_t!(matches, stringify!($arg), $($arg_type_tt)+) }
)
}
)) {
raw_args.$arg = some;
}
)*
)*
// Subcommands
$(
if let Some(submatches) = matches.subcommand_matches(&underscore_to_hyphen!(&stringify!($subc)[4..])) {
raw_args.$subc = true;
// Globals
raw_args.hydrate_with_globals(&submatches)?;
// Subcommand flags
$(
raw_args.$subc_flag = submatches.is_present(&stringify!($subc_flag));
@@ -643,8 +703,6 @@ macro_rules! usage {
if let Some(subsubmatches) = submatches.subcommand_matches(&underscore_to_hyphen!(&stringify!($subc_subc)[stringify!($subc).len()+1..])) {
raw_args.$subc_subc = true;
// Globals
raw_args.hydrate_with_globals(&subsubmatches)?;
// Sub-subcommand flags
$(
raw_args.$subc_subc_flag = subsubmatches.is_present(&stringify!($subc_subc_flag));

View File

@@ -1,3 +1,3 @@
Parity. Ethereum Client.
By Wood/Paronyan/Kotewicz/Drwięga/Volf et al.
Copyright 2015, 2016, 2017 Parity Technologies (UK) Ltd
Copyright 2015, 2016, 2017, 2018 Parity Technologies (UK) Ltd

View File

@@ -1,6 +1,6 @@
Parity
version {}
Copyright 2015, 2016, 2017 Parity Technologies (UK) Ltd
Copyright 2015, 2016, 2017, 2018 Parity Technologies (UK) Ltd
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

View File

@@ -586,7 +586,12 @@ impl Configuration {
let mut extra_embed = dev_ui.clone();
match self.ui_hosts() {
// In case host validation is disabled allow all frame ancestors
None => extra_embed.push(("*".to_owned(), ui_port)),
None => {
// NOTE Chrome does not seem to support "*:<port>"
// we use `http(s)://*:<port>` instead.
extra_embed.push(("http://*".to_owned(), ui_port));
extra_embed.push(("https://*".to_owned(), ui_port));
},
Some(hosts) => extra_embed.extend(hosts.into_iter().filter_map(|host| {
let mut it = host.split(":");
let host = it.next();

View File

@@ -16,6 +16,8 @@
use std::fmt;
use std::sync::{Arc, Weak};
use std::time::{Duration, Instant};
use std::thread;
use std::net::{TcpListener};
use ctrlc::CtrlC;
@@ -171,8 +173,10 @@ impl ::local_store::NodeInfo for FullNodeInfo {
}
}
type LightClient = ::light::client::Client<::light_helpers::EpochFetch>;
// helper for light execution.
fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> Result<(bool, Option<String>), String> {
fn execute_light_impl(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> Result<((bool, Option<String>), Weak<LightClient>), String> {
use light::client as light_client;
use ethsync::{LightSyncParams, LightSync, ManageNetwork};
use parking_lot::{Mutex, RwLock};
@@ -237,8 +241,9 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
let service = light_client::Service::start(config, &spec, fetch, &db_dirs.client_path(algorithm), cache.clone())
.map_err(|e| format!("Error starting light client: {}", e))?;
let client = service.client();
let txq = Arc::new(RwLock::new(::light::transaction_queue::TransactionQueue::default()));
let provider = ::light::provider::LightProvider::new(service.client().clone(), txq.clone());
let provider = ::light::provider::LightProvider::new(client.clone(), txq.clone());
// start network.
// set up bootnodes
@@ -275,7 +280,7 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
// queue cull service.
let queue_cull = Arc::new(::light_helpers::QueueCull {
client: service.client().clone(),
client: client.clone(),
sync: light_sync.clone(),
on_demand: on_demand.clone(),
txq: txq.clone(),
@@ -299,7 +304,7 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
let signer_service = Arc::new(signer::new_service(&cmd.ws_conf, &cmd.ui_conf, &cmd.logger_config));
let (node_health, dapps_deps) = {
let contract_client = Arc::new(::dapps::LightRegistrar {
client: service.client().clone(),
client: client.clone(),
sync: light_sync.clone(),
on_demand: on_demand.clone(),
});
@@ -342,7 +347,7 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
let dapps_service = dapps::service(&dapps_middleware);
let deps_for_rpc_apis = Arc::new(rpc_apis::LightDependencies {
signer_service: signer_service,
client: service.client().clone(),
client: client.clone(),
sync: light_sync.clone(),
net: light_sync.clone(),
health: node_health,
@@ -382,7 +387,7 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
// the informant
let informant = Arc::new(Informant::new(
LightNodeInformantData {
client: service.client().clone(),
client: client.clone(),
sync: light_sync.clone(),
cache: cache,
},
@@ -397,26 +402,13 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
let res = wait_for_exit(None, None, can_restart);
informant.shutdown();
Ok(res)
// Create a weak reference to the client so that we can wait on shutdown until it is dropped
let weak_client = Arc::downgrade(&client);
Ok((res, weak_client))
}
pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> Result<(bool, Option<String>), String> {
if cmd.ui && cmd.dapps_conf.enabled {
// Check if Parity is already running
let addr = format!("{}:{}", cmd.ui_conf.interface, cmd.ui_conf.port);
if !TcpListener::bind(&addr as &str).is_ok() {
return open_ui(&cmd.ws_conf, &cmd.ui_conf, &cmd.logger_config).map(|_| (false, None));
}
}
// increase max number of open files
raise_fd_limit();
// run as light client.
if cmd.light {
return execute_light(cmd, can_restart, logger);
}
pub fn execute_impl(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> Result<((bool, Option<String>), Weak<Client>), String> {
// load spec
let spec = cmd.spec.spec(&cmd.dirs.cache)?;
@@ -855,6 +847,9 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
open_dapp(&cmd.dapps_conf, &cmd.http_conf, &dapp)?;
}
// Create a weak reference to the client so that we can wait on shutdown until it is dropped
let weak_client = Arc::downgrade(&client);
// Handle exit
let restart = wait_for_exit(Some(updater), Some(client), can_restart);
@@ -868,7 +863,33 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
// just Arc is dropping here, to allow other reference release in its default time
drop(informant);
Ok(restart)
Ok((restart, weak_client))
}
pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> Result<(bool, Option<String>), String> {
if cmd.ui && cmd.dapps_conf.enabled {
// Check if Parity is already running
let addr = format!("{}:{}", cmd.ui_conf.interface, cmd.ui_conf.port);
if !TcpListener::bind(&addr as &str).is_ok() {
return open_ui(&cmd.ws_conf, &cmd.ui_conf, &cmd.logger_config).map(|_| (false, None));
}
}
// increase max number of open files
raise_fd_limit();
fn wait<T>(res: Result<((bool, Option<String>), Weak<T>), String>) -> Result<(bool, Option<String>), String> {
res.map(|(restart, weak_client)| {
wait_for_drop(weak_client);
restart
})
}
if cmd.light {
wait(execute_light_impl(cmd, can_restart, logger))
} else {
wait(execute_impl(cmd, can_restart, logger))
}
}
#[cfg(not(windows))]
@@ -1001,3 +1022,27 @@ fn wait_for_exit(
let _ = exit.1.wait(&mut l);
l.clone()
}
fn wait_for_drop<T>(w: Weak<T>) {
let sleep_duration = Duration::from_secs(1);
let warn_timeout = Duration::from_secs(60);
let max_timeout = Duration::from_secs(300);
let instant = Instant::now();
let mut warned = false;
while instant.elapsed() < max_timeout {
if w.upgrade().is_none() {
return;
}
if !warned && instant.elapsed() > warn_timeout {
warned = true;
warn!("Shutdown is taking longer than expected.");
}
thread::sleep(sleep_duration);
}
warn!("Shutdown timeout reached, exiting uncleanly.");
}

View File

@@ -147,19 +147,30 @@ impl LightFetch {
Err(e) => return Box::new(future::err(e)),
};
let maybe_future = self.sync.with_context(move |ctx| {
Box::new(self.on_demand.request_raw(ctx, reqs)
.expect("all back-references known to be valid; qed")
.map(|res| extract_header(&res, header_ref)
.expect("these responses correspond to requests that header_ref belongs to. \
therefore it will not fail; qed"))
.map_err(errors::on_demand_cancel))
});
match maybe_future {
Some(recv) => recv,
None => Box::new(future::err(errors::network_disabled()))
}
self.send_requests(reqs, |res|
extract_header(&res, header_ref)
.expect("these responses correspond to requests that header_ref belongs to \
therefore it will not fail; qed")
)
}
/// Helper for getting contract code at a given block.
pub fn code(&self, address: Address, id: BlockId) -> BoxFuture<Vec<u8>> {
let mut reqs = Vec::new();
let header_ref = match self.make_header_requests(id, &mut reqs) {
Ok(r) => r,
Err(e) => return Box::new(future::err(e)),
};
reqs.push(request::Account { header: header_ref.clone(), address: address }.into());
let account_idx = reqs.len() - 1;
reqs.push(request::Code { header: header_ref, code_hash: Field::back_ref(account_idx, 0) }.into());
self.send_requests(reqs, |mut res| match res.pop() {
Some(OnDemandResponse::Code(code)) => code,
_ => panic!("responses correspond directly with requests in amount and type; qed"),
})
}
/// Helper for getting account info at a given block.
@@ -173,20 +184,10 @@ impl LightFetch {
reqs.push(request::Account { header: header_ref, address: address }.into());
let maybe_future = self.sync.with_context(move |ctx| {
Box::new(self.on_demand.request_raw(ctx, reqs)
.expect("all back-references known to be valid; qed")
.map(|mut res| match res.pop() {
Some(OnDemandResponse::Account(acc)) => acc,
_ => panic!("responses correspond directly with requests in amount and type; qed"),
})
.map_err(errors::on_demand_cancel))
});
match maybe_future {
Some(recv) => recv,
None => Box::new(future::err(errors::network_disabled()))
}
self.send_requests(reqs, |mut res|match res.pop() {
Some(OnDemandResponse::Account(acc)) => acc,
_ => panic!("responses correspond directly with requests in amount and type; qed"),
})
}
/// Helper for getting proved execution.
@@ -277,20 +278,10 @@ impl LightFetch {
reqs.push(request::Body(header_ref).into());
let maybe_future = self.sync.with_context(move |ctx| {
Box::new(self.on_demand.request_raw(ctx, reqs)
.expect(NO_INVALID_BACK_REFS)
.map(|mut res| match res.pop() {
Some(OnDemandResponse::Body(b)) => b,
_ => panic!("responses correspond directly with requests in amount and type; qed"),
})
.map_err(errors::on_demand_cancel))
});
match maybe_future {
Some(recv) => recv,
None => Box::new(future::err(errors::network_disabled()))
}
self.send_requests(reqs, |mut res| match res.pop() {
Some(OnDemandResponse::Body(b)) => b,
_ => panic!("responses correspond directly with requests in amount and type; qed"),
})
}
/// Get the block receipts. Fails on unknown block ID.
@@ -303,20 +294,10 @@ impl LightFetch {
reqs.push(request::BlockReceipts(header_ref).into());
let maybe_future = self.sync.with_context(move |ctx| {
Box::new(self.on_demand.request_raw(ctx, reqs)
.expect(NO_INVALID_BACK_REFS)
.map(|mut res| match res.pop() {
Some(OnDemandResponse::Receipts(b)) => b,
_ => panic!("responses correspond directly with requests in amount and type; qed"),
})
.map_err(errors::on_demand_cancel))
});
match maybe_future {
Some(recv) => recv,
None => Box::new(future::err(errors::network_disabled()))
}
self.send_requests(reqs, |mut res| match res.pop() {
Some(OnDemandResponse::Receipts(b)) => b,
_ => panic!("responses correspond directly with requests in amount and type; qed"),
})
}
/// Get transaction logs
@@ -433,6 +414,23 @@ impl LightFetch {
Either::B(extract_transaction)
}))
}
fn send_requests<T, F>(&self, reqs: Vec<OnDemandRequest>, parse_response: F) -> BoxFuture<T> where
F: FnOnce(Vec<OnDemandResponse>) -> T + Send + 'static,
T: Send + 'static,
{
let maybe_future = self.sync.with_context(move |ctx| {
Box::new(self.on_demand.request_raw(ctx, reqs)
.expect(NO_INVALID_BACK_REFS)
.map(parse_response)
.map_err(errors::on_demand_cancel))
});
match maybe_future {
Some(recv) => recv,
None => Box::new(future::err(errors::network_disabled()))
}
}
}
#[derive(Clone)]

View File

@@ -349,8 +349,8 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> {
}))
}
fn code_at(&self, _address: RpcH160, _num: Trailing<BlockNumber>) -> BoxFuture<Bytes> {
Box::new(future::err(errors::unimplemented(None)))
fn code_at(&self, address: RpcH160, num: Trailing<BlockNumber>) -> BoxFuture<Bytes> {
Box::new(self.fetcher().code(address.into(), num.unwrap_or_default().into()).map(Into::into))
}
fn send_raw_transaction(&self, raw: Bytes) -> Result<RpcH256> {

View File

@@ -208,7 +208,12 @@ impl Parity for ParityClient {
}
fn registry_address(&self) -> Result<Option<H160>> {
Err(errors::light_unimplemented(None))
let reg = self.light_dispatch.client.engine().params().registrar;
if reg == Default::default() {
Ok(None)
} else {
Ok(Some(reg.into()))
}
}
fn rpc_settings(&self) -> Result<RpcSettings> {

View File

@@ -270,15 +270,33 @@ case $BUILD_PLATFORM in
push_release
;;
x86_64-unknown-snap-gnu)
cd snap
ARC="amd64"
EXT="snap"
rm -rf *snap
sed -i 's/master/'"$VER"'/g' snapcraft.yaml
snapcraft
cp "parity_"$CI_BUILD_REF_NAME"_amd64.snap" "parity_"$VER"_amd64.snap"
snapcraft clean
echo "Prepare snapcraft.yaml for build on Gitlab CI in Docker image"
sed -i 's/git/'"$VER"'/g' snap/snapcraft.yaml
if [[ "$CI_BUILD_REF_NAME" = "stable" ]];
then
sed -i -e 's/grade: devel/grade: stable/' snap/snapcraft.yaml;
fi
mv -f snap/snapcraft.yaml snapcraft.yaml
snapcraft -d
snapcraft_login=$(expect -c "
spawn snapcraft login
expect \"Email:\"
send \"$SNAP_EMAIL\n\"
expect \"Password:\"
send \"$SNAP_PASS\n\"
expect \"\$\"
")
echo "$snapcraft_login"
snapcraft push "parity_"$VER"_amd64.snap"
snapcraft status parity
snapcraft logout
md5sum "parity_"$VER"_amd64.snap" > "parity_"$VER"_amd64.snap.md5"
push_binaries
echo "add artifacts to archive"
rm -rf parity.zip
zip -r parity.zip "parity_"$VER"_amd64.snap" "parity_"$VER"_amd64.snap.md5"
;;
x86_64-pc-windows-msvc)
set_env_win

View File

@@ -4,5 +4,5 @@ Encoding=UTF-8
Name=parity
Comment=Fast, light, robust Ethereum implementation
Exec=parity
Icon=${SNAP}/meta/gui/icon.png
Icon=/usr/share/pixmaps/icon.png
Terminal=true

View File

@@ -13,9 +13,20 @@ confinement: strict
apps:
parity:
command: parity
plugs: [network, network-bind, mount-observe, x11, unity7]
plugs: [home, network, network-bind, mount-observe, x11, unity7, desktop, desktop-legacy, wayland]
desktop: usr/share/applications/parity.desktop
icon: snap/gui/icon.png
parts:
desktop-icon:
source: ./snap
plugin: nil
prepare: |
mkdir -p $SNAPCRAFT_PART_INSTALL/usr/share/applications
mkdir -p $SNAPCRAFT_PART_INSTALL/usr/share/pixmaps
cp -v gui/parity.desktop $SNAPCRAFT_PART_INSTALL/usr/share/applications/
cp -v gui/icon.png $SNAPCRAFT_PART_INSTALL/usr/share/pixmaps/
parity:
source: .
plugin: rust

View File

@@ -170,7 +170,18 @@ pub struct AttachedProtocol {
}
impl AttachedProtocol {
fn register(&self, _network: &NetworkService) {}
fn register(&self, network: &NetworkService) {
let res = network.register_protocol(
self.handler.clone(),
self.protocol_id,
self.packet_count,
self.versions
);
if let Err(e) = res {
warn!(target: "sync", "Error attaching protocol {:?}: {:?}", self.protocol_id, e);
}
}
}
/// EthSync initialization parameters.

View File

@@ -522,6 +522,10 @@ impl BlockDownloader {
trace!(target: "sync", "Unknown new block parent, restarting sync");
break;
},
Err(BlockImportError::Block(BlockError::TemporarilyInvalid(_))) => {
debug!(target: "sync", "Block temporarily invalid, restarting sync");
break;
},
Err(e) => {
debug!(target: "sync", "Bad block {:?} : {:?}", h, e);
bad = true;

View File

@@ -32,7 +32,7 @@ use std::cmp;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::path::{PathBuf, Path};
use std::{mem, fs, io};
use std::{fs, io, mem, result};
use parking_lot::{Mutex, MutexGuard, RwLock};
use rocksdb::{
@@ -257,7 +257,25 @@ pub struct Database {
flushing_lock: Mutex<bool>,
}
#[inline]
fn check_for_corruption<T, P: AsRef<Path>>(path: P, res: result::Result<T, String>) -> result::Result<T, String> {
if let Err(ref s) = res {
if s.starts_with("Corruption:") {
warn!("DB corrupted: {}. Repair will be triggered on next restart", s);
let _ = fs::File::create(path.as_ref().join(Database::CORRUPTION_FILE_NAME));
}
}
res
}
fn is_corrupted(s: &str) -> bool {
s.starts_with("Corruption:") || s.starts_with("Invalid argument: You have to open all column families")
}
impl Database {
const CORRUPTION_FILE_NAME: &'static str = "CORRUPTED";
/// Open database with default settings.
pub fn open_default(path: &str) -> Result<Database> {
Database::open(&DatabaseConfig::default(), path)
@@ -287,6 +305,14 @@ impl Database {
block_opts.set_cache(cache);
}
// attempt database repair if it has been previously marked as corrupted
let db_corrupted = Path::new(path).join(Database::CORRUPTION_FILE_NAME);
if db_corrupted.exists() {
warn!("DB has been previously marked as corrupted, attempting repair");
DB::repair(&opts, path)?;
fs::remove_file(db_corrupted)?;
}
let columns = config.columns.unwrap_or(0) as usize;
let mut cf_options = Vec::with_capacity(columns);
@@ -306,12 +332,11 @@ impl Database {
let mut cfs: Vec<Column> = Vec::new();
let db = match config.columns {
Some(columns) => {
Some(_) => {
match DB::open_cf(&opts, path, &cfnames, &cf_options) {
Ok(db) => {
cfs = cfnames.iter().map(|n| db.cf_handle(n)
.expect("rocksdb opens a cf_handle for each cfname; qed")).collect();
assert!(cfs.len() == columns as usize);
Ok(db)
}
Err(_) => {
@@ -321,7 +346,7 @@ impl Database {
cfs = cfnames.iter().enumerate().map(|(i, n)| db.create_cf(n, &cf_options[i])).collect::<::std::result::Result<_, _>>()?;
Ok(db)
},
err @ Err(_) => err,
err => err,
}
}
}
@@ -331,14 +356,18 @@ impl Database {
let db = match db {
Ok(db) => db,
Err(ref s) if s.starts_with("Corruption:") => {
info!("{}", s);
info!("Attempting DB repair for {}", path);
Err(ref s) if is_corrupted(s) => {
warn!("DB corrupted: {}, attempting repair", s);
DB::repair(&opts, path)?;
match cfnames.is_empty() {
true => DB::open(&opts, path)?,
false => DB::open_cf(&opts, path, &cfnames, &cf_options)?
false => {
let db = DB::open_cf(&opts, path, &cfnames, &cf_options)?;
cfs = cfnames.iter().map(|n| db.cf_handle(n)
.expect("rocksdb opens a cf_handle for each cfname; qed")).collect();
db
},
}
},
Err(s) => { return Err(s.into()); }
@@ -425,7 +454,11 @@ impl Database {
}
}
}
db.write_opt(batch, &self.write_opts)?;
check_for_corruption(
&self.path,
db.write_opt(batch, &self.write_opts))?;
for column in self.flushing.write().iter_mut() {
column.clear();
column.shrink_to_fit();
@@ -471,7 +504,10 @@ impl Database {
},
}
}
db.write_opt(batch, &self.write_opts).map_err(Into::into)
check_for_corruption(
&self.path,
db.write_opt(batch, &self.write_opts)).map_err(Into::into)
},
None => Err("Database is closed".into())
}

View File

@@ -31,7 +31,9 @@ ethcore-logger = { path ="../../logger" }
ipnetwork = "0.12.6"
keccak-hash = { path = "../hash" }
snappy = { git = "https://github.com/paritytech/rust-snappy" }
serde = "1.0"
serde_json = "1.0"
serde_derive = "1.0"
error-chain = { version = "0.11", default-features = false }
[dev-dependencies]

View File

@@ -719,7 +719,7 @@ impl Host {
let address = {
let mut nodes = self.nodes.write();
if let Some(node) = nodes.get_mut(id) {
node.last_attempted = Some(::time::now());
node.attempts += 1;
node.endpoint.address
}
else {
@@ -738,6 +738,7 @@ impl Host {
}
}
};
if let Err(e) = self.create_connection(socket, Some(id), io) {
debug!(target: "network", "Can't create connection: {:?}", e);
}
@@ -1281,4 +1282,3 @@ fn host_client_url() {
let host: Host = Host::new(config, Arc::new(NetworkStats::new()), None).unwrap();
assert!(host.local_url().starts_with("enode://101b3ef5a4ea7a1c7928e24c4c75fd053c235d7b80c22ae5c03d145d0ac7396e2a4ffff9adee3133a7b05044a5cee08115fd65145e5165d646bde371010d803c@"));
}

View File

@@ -80,14 +80,16 @@ extern crate path;
extern crate ethcore_logger;
extern crate ipnetwork;
extern crate keccak_hash as hash;
extern crate serde;
extern crate serde_json;
extern crate snappy;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
#[cfg(test)]
extern crate ethcore_devtools as devtools;
@@ -213,4 +215,3 @@ pub enum AllowIP {
/// Block all addresses
None,
}

View File

@@ -14,25 +14,20 @@
// 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::mem;
use std::slice::from_raw_parts;
use std::net::{SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr};
use std::hash::{Hash, Hasher};
use std::str::{FromStr};
use std::collections::{HashMap, HashSet};
use std::fmt::{Display, Formatter};
use std::path::{PathBuf};
use std::fmt;
use std::fs;
use std::io::{Read, Write};
use bigint::hash::*;
use std::fmt::{self, Display, Formatter};
use std::hash::{Hash, Hasher};
use std::net::{SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr};
use std::path::PathBuf;
use std::str::FromStr;
use std::{fs, mem, slice};
use bigint::hash::H512;
use rlp::*;
use time::Tm;
use error::{Error, ErrorKind};
use {AllowIP, IpFilter};
use discovery::{TableUpdates, NodeEntry};
use ip_utils::*;
use serde_json::Value;
use serde_json;
/// Node public key
pub type NodeId = H512;
@@ -80,7 +75,7 @@ impl NodeEndpoint {
4 => Ok(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(addr_bytes[0], addr_bytes[1], addr_bytes[2], addr_bytes[3]), tcp_port))),
16 => unsafe {
let o: *const u16 = mem::transmute(addr_bytes.as_ptr());
let o = from_raw_parts(o, 8);
let o = slice::from_raw_parts(o, 8);
Ok(SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7]), tcp_port, 0, 0)))
},
_ => Err(DecoderError::RlpInconsistentLengthAndData)
@@ -95,7 +90,7 @@ impl NodeEndpoint {
}
SocketAddr::V6(a) => unsafe {
let o: *const u8 = mem::transmute(a.ip().segments().as_ptr());
rlp.append(&from_raw_parts(o, 16));
rlp.append(&slice::from_raw_parts(o, 16));
}
};
rlp.append(&self.udp_port);
@@ -143,18 +138,30 @@ pub struct Node {
pub id: NodeId,
pub endpoint: NodeEndpoint,
pub peer_type: PeerType,
pub attempts: u32,
pub failures: u32,
pub last_attempted: Option<Tm>,
}
const DEFAULT_FAILURE_PERCENTAGE: usize = 50;
impl Node {
pub fn new(id: NodeId, endpoint: NodeEndpoint) -> Node {
Node {
id: id,
endpoint: endpoint,
peer_type: PeerType::Optional,
attempts: 0,
failures: 0,
last_attempted: None,
}
}
/// Returns the node's failure percentage (0..100) in buckets of 5%. If there are 0 connection attempts for this
/// node the default failure percentage is returned (50%).
pub fn failure_percentage(&self) -> usize {
if self.attempts == 0 {
DEFAULT_FAILURE_PERCENTAGE
} else {
(self.failures * 100 / self.attempts / 5 * 5) as usize
}
}
}
@@ -184,7 +191,7 @@ impl FromStr for Node {
id: id,
endpoint: endpoint,
peer_type: PeerType::Optional,
last_attempted: None,
attempts: 0,
failures: 0,
})
}
@@ -203,6 +210,9 @@ impl Hash for Node {
}
}
const MAX_NODES: usize = 1024;
const NODES_FILE: &str = "nodes.json";
/// Node table backed by disk file.
pub struct NodeTable {
nodes: HashMap<NodeId, Node>,
@@ -221,23 +231,37 @@ impl NodeTable {
/// Add a node to table
pub fn add_node(&mut self, mut node: Node) {
// preserve failure counter
let failures = self.nodes.get(&node.id).map_or(0, |n| n.failures);
// preserve attempts and failure counter
let (attempts, failures) =
self.nodes.get(&node.id).map_or((0, 0), |n| (n.attempts, n.failures));
node.attempts = attempts;
node.failures = failures;
self.nodes.insert(node.id.clone(), node);
}
/// Returns node ids sorted by number of failures
/// Returns node ids sorted by failure percentage, for nodes with the same failure percentage the absolute number of
/// failures is considered.
pub fn nodes(&self, filter: IpFilter) -> Vec<NodeId> {
let mut refs: Vec<&Node> = self.nodes.values().filter(|n| !self.useless_nodes.contains(&n.id) && n.endpoint.is_allowed(&filter)).collect();
refs.sort_by(|a, b| a.failures.cmp(&b.failures));
refs.iter().map(|n| n.id.clone()).collect()
let mut refs: Vec<&Node> = self.nodes.values()
.filter(|n| !self.useless_nodes.contains(&n.id))
.filter(|n| n.endpoint.is_allowed(&filter))
.collect();
refs.sort_by(|a, b| {
a.failure_percentage().cmp(&b.failure_percentage())
.then_with(|| a.failures.cmp(&b.failures))
.then_with(|| b.attempts.cmp(&a.attempts)) // we use reverse ordering for number of attempts
});
refs.into_iter().map(|n| n.id).collect()
}
/// Unordered list of all entries
pub fn unordered_entries(&self) -> Vec<NodeEntry> {
// preserve failure counter
self.nodes.values().map(|n| NodeEntry { endpoint: n.endpoint.clone(), id: n.id.clone() }).collect()
self.nodes.values().map(|n| NodeEntry {
endpoint: n.endpoint.clone(),
id: n.id.clone(),
}).collect()
}
/// Get particular node
@@ -270,7 +294,7 @@ impl NodeTable {
}
}
/// Mark as useless, no furter attempts to connect until next call to `clear_useless`.
/// Mark as useless, no further attempts to connect until next call to `clear_useless`.
pub fn mark_as_useless(&mut self, id: &NodeId) {
self.useless_nodes.insert(id.clone());
}
@@ -282,77 +306,62 @@ impl NodeTable {
/// Save the nodes.json file.
pub fn save(&self) {
if let Some(ref path) = self.path {
let mut path_buf = PathBuf::from(path);
if let Err(e) = fs::create_dir_all(path_buf.as_path()) {
warn!("Error creating node table directory: {:?}", e);
return;
};
path_buf.push("nodes.json");
let mut json = String::new();
json.push_str("{\n");
json.push_str("\"nodes\": [\n");
let node_ids = self.nodes(IpFilter::default());
for i in 0 .. node_ids.len() {
let node = self.nodes.get(&node_ids[i]).expect("self.nodes() only returns node IDs from self.nodes");
json.push_str(&format!("\t{{ \"url\": \"{}\", \"failures\": {} }}{}\n", node, node.failures, if i == node_ids.len() - 1 {""} else {","}))
}
json.push_str("]\n");
json.push_str("}");
let mut file = match fs::File::create(path_buf.as_path()) {
Ok(file) => file,
Err(e) => {
warn!("Error creating node table file: {:?}", e);
return;
let mut path = match self.path {
Some(ref path) => PathBuf::from(path),
None => return,
};
if let Err(e) = fs::create_dir_all(&path) {
warn!("Error creating node table directory: {:?}", e);
return;
}
path.push(NODES_FILE);
let node_ids = self.nodes(IpFilter::default());
let nodes = node_ids.into_iter()
.map(|id| self.nodes.get(&id).expect("self.nodes() only returns node IDs from self.nodes"))
.take(MAX_NODES)
.map(|node| node.clone())
.map(Into::into)
.collect();
let table = json::NodeTable { nodes };
match fs::File::create(&path) {
Ok(file) => {
if let Err(e) = serde_json::to_writer_pretty(file, &table) {
warn!("Error writing node table file: {:?}", e);
}
};
if let Err(e) = file.write(&json.into_bytes()) {
warn!("Error writing node table file: {:?}", e);
},
Err(e) => {
warn!("Error creating node table file: {:?}", e);
}
}
}
fn load(path: Option<String>) -> HashMap<NodeId, Node> {
let mut nodes: HashMap<NodeId, Node> = HashMap::new();
if let Some(path) = path {
let mut path_buf = PathBuf::from(path);
path_buf.push("nodes.json");
let mut file = match fs::File::open(path_buf.as_path()) {
Ok(file) => file,
Err(e) => {
debug!("Error opening node table file: {:?}", e);
return nodes;
}
};
let mut buf = String::new();
match file.read_to_string(&mut buf) {
Ok(_) => {},
Err(e) => {
warn!("Error reading node table file: {:?}", e);
return nodes;
}
}
let json: Value = match ::serde_json::from_str(&buf) {
Ok(json) => json,
Err(e) => {
warn!("Error parsing node table file: {:?}", e);
return nodes;
}
};
if let Some(list) = json.as_object().and_then(|o| o.get("nodes")).and_then(|n| n.as_array()) {
for n in list.iter().filter_map(|n| n.as_object()) {
if let Some(url) = n.get("url").and_then(|u| u.as_str()) {
if let Ok(mut node) = Node::from_str(url) {
if let Some(failures) = n.get("failures").and_then(|f| f.as_u64()) {
node.failures = failures as u32;
}
nodes.insert(node.id.clone(), node);
}
}
}
}
let path = match path {
Some(path) => PathBuf::from(path).join(NODES_FILE),
None => return Default::default(),
};
let file = match fs::File::open(&path) {
Ok(file) => file,
Err(e) => {
debug!("Error opening node table file: {:?}", e);
return Default::default();
},
};
let res: Result<json::NodeTable, _> = serde_json::from_reader(file);
match res {
Ok(table) => {
table.nodes.into_iter()
.filter_map(|n| n.into_node())
.map(|n| (n.id.clone(), n))
.collect()
},
Err(e) => {
warn!("Error reading node table file: {:?}", e);
Default::default()
},
}
nodes
}
}
@@ -364,13 +373,51 @@ impl Drop for NodeTable {
/// Check if node url is valid
pub fn validate_node_url(url: &str) -> Option<Error> {
use std::str::FromStr;
match Node::from_str(url) {
Ok(_) => None,
Err(e) => Some(e)
}
}
mod json {
use super::*;
#[derive(Serialize, Deserialize)]
pub struct NodeTable {
pub nodes: Vec<Node>,
}
#[derive(Serialize, Deserialize)]
pub struct Node {
pub url: String,
pub attempts: u32,
pub failures: u32,
}
impl Node {
pub fn into_node(self) -> Option<super::Node> {
match super::Node::from_str(&self.url) {
Ok(mut node) => {
node.attempts = self.attempts;
node.failures = self.failures;
Some(node)
},
_ => None,
}
}
}
impl<'a> From<&'a super::Node> for Node {
fn from(node: &'a super::Node) -> Self {
Node {
url: format!("{}", node),
attempts: node.attempts,
failures: node.failures,
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
@@ -408,26 +455,42 @@ mod tests {
}
#[test]
fn table_failure_order() {
fn table_failure_percentage_order() {
let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap();
let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap();
let node3 = Node::from_str("enode://c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap();
let node4 = Node::from_str("enode://d979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap();
let id1 = H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
let id2 = H512::from_str("b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
let id3 = H512::from_str("c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
let id4 = H512::from_str("d979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
let mut table = NodeTable::new(None);
table.add_node(node3);
table.add_node(node1);
table.add_node(node2);
table.add_node(node3);
table.add_node(node4);
// node 1 - failure percentage 100%
table.get_mut(&id1).unwrap().attempts = 2;
table.note_failure(&id1);
table.note_failure(&id1);
// node2 - failure percentage 33%
table.get_mut(&id2).unwrap().attempts = 3;
table.note_failure(&id2);
// node3 - failure percentage 0%
table.get_mut(&id3).unwrap().attempts = 1;
// node4 - failure percentage 50% (default when no attempts)
let r = table.nodes(IpFilter::default());
assert_eq!(r[0][..], id3[..]);
assert_eq!(r[1][..], id2[..]);
assert_eq!(r[2][..], id1[..]);
assert_eq!(r[2][..], id4[..]);
assert_eq!(r[3][..], id1[..]);
}
#[test]
@@ -441,6 +504,9 @@ mod tests {
let mut table = NodeTable::new(Some(tempdir.path().to_str().unwrap().to_owned()));
table.add_node(node1);
table.add_node(node2);
table.get_mut(&id1).unwrap().attempts = 1;
table.get_mut(&id2).unwrap().attempts = 1;
table.note_failure(&id2);
}

View File

@@ -1,7 +1,7 @@
[package]
name = "parity-version"
# NOTE: this value is used for Parity version string.
version = "1.9.0"
version = "1.9.2"
authors = ["Parity Technologies <admin@parity.io>"]
build = "build.rs"