Merge branch 'master' into auth-round

This commit is contained in:
keorn 2016-11-03 16:51:38 +00:00
commit 12125dcfee
68 changed files with 1135 additions and 361 deletions

View File

@ -136,7 +136,6 @@ linux-armv7:
stage: build
image: ethcore/rust-armv7:latest
only:
- master
- beta
- tags
- stable
@ -176,7 +175,6 @@ linux-arm:
stage: build
image: ethcore/rust-arm:latest
only:
- master
- beta
- tags
- stable
@ -248,7 +246,6 @@ linux-aarch64:
stage: build
image: ethcore/rust-aarch64:latest
only:
- master
- beta
- tags
- stable
@ -287,7 +284,6 @@ linux-aarch64:
darwin:
stage: build
only:
- master
- beta
- tags
- stable
@ -308,7 +304,6 @@ darwin:
windows:
stage: build
only:
- master
- beta
- tags
- stable
@ -322,6 +317,8 @@ windows:
- curl -sL --url "https://github.com/ethcore/win-build/raw/master/SimpleFC.dll" -o nsis\SimpleFC.dll
- curl -sL --url "https://github.com/ethcore/win-build/raw/master/vc_redist.x64.exe" -o nsis\vc_redist.x64.exe
- signtool sign /f %keyfile% /p %certpass% target\release\parity.exe
- msbuild windows\ptray\ptray.vcxproj /p:Platform=x86 /p:Configuration=Release
- signtool sign /f %keyfile% /p %certpass% windows\ptray\release\ptray.exe
- cd nsis
- makensis.exe installer.nsi
- copy installer.exe InstallParity.exe
@ -393,30 +390,14 @@ js-release:
- ./js/scripts/release.sh
tags:
- javascript
js-lint:
js-tests:
stage: build
image: ethcore/javascript:latest
before_script:
- ./js/scripts/install-deps.sh
script:
- ./js/scripts/lint.sh
tags:
- javascript-test
js-test:
stage: build
image: ethcore/javascript:latest
before_script:
- ./js/scripts/install-deps.sh
script:
- ./js/scripts/test.sh
tags:
- javascript-test
js-pack:
stage: build
image: ethcore/javascript:latest
before_script:
- ./js/scripts/install-deps.sh
script:
- ./js/scripts/build.sh
tags:
- javascript-test

101
Cargo.lock generated
View File

@ -185,7 +185,7 @@ version = "1.1.1"
source = "git+https://github.com/ethcore/rust-ctrlc.git#f4927770f89eca80ec250911eea3adcbf579ac48"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -194,7 +194,7 @@ name = "daemonize"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -244,7 +244,7 @@ source = "git+https://github.com/ethcore/rust-secp256k1#a9a0b1be1f39560ca86e8fc8
dependencies = [
"arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -352,6 +352,7 @@ dependencies = [
"serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_codegen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"zip 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
@ -370,7 +371,7 @@ version = "1.4.0"
dependencies = [
"crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.0 (git+https://github.com/carllerche/mio)",
"mio 0.6.1 (git+https://github.com/carllerche/mio)",
"parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -458,9 +459,9 @@ dependencies = [
"ethcrypto 0.1.0",
"ethkey 0.2.0",
"igd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.0 (git+https://github.com/carllerche/mio)",
"mio 0.6.1 (git+https://github.com/carllerche/mio)",
"parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rlp 0.1.0",
@ -554,7 +555,7 @@ dependencies = [
"heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"lru-cache 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -618,7 +619,7 @@ dependencies = [
"ethkey 0.2.0",
"itertools 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
@ -663,7 +664,7 @@ dependencies = [
name = "fdlimit"
version = "0.1.0"
dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -681,7 +682,7 @@ name = "flate2"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"miniz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -802,7 +803,7 @@ version = "0.1.1"
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.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -894,7 +895,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.15"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -930,7 +931,7 @@ name = "memchr"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -958,7 +959,7 @@ version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -967,7 +968,7 @@ version = "0.5.1"
source = "git+https://github.com/ethcore/mio?branch=v0.5.x#3842d3b250ffd7bd9b16f9586b875ddcbac2b0dd"
dependencies = [
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
@ -983,7 +984,7 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
@ -999,7 +1000,7 @@ version = "0.6.0-dev"
source = "git+https://github.com/ethcore/mio?branch=timer-fix#31eccc40ece3d47abaefaf23bb2114033175b972"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1010,16 +1011,16 @@ dependencies = [
[[package]]
name = "mio"
version = "0.6.0"
source = "git+https://github.com/carllerche/mio#9f17b70d6fecbf912168267ea74cf536f2cba705"
version = "0.6.1"
source = "git+https://github.com/carllerche/mio#56f8663510196fdca04bdf7c5f4d60b24297826f"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1050,7 +1051,7 @@ name = "nanomsg"
version = "0.5.1"
source = "git+https://github.com/ethcore/nanomsg.rs.git#c40fe442c9afaea5b38009a3d992ca044dcceb00"
dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"nanomsg-sys 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)",
]
@ -1060,7 +1061,7 @@ version = "0.5.0"
source = "git+https://github.com/ethcore/nanomsg.rs.git#c40fe442c9afaea5b38009a3d992ca044dcceb00"
dependencies = [
"gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1070,7 +1071,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1081,7 +1082,7 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1091,7 +1092,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nix"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1181,7 +1195,7 @@ name = "num_cpus"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1235,7 +1249,7 @@ dependencies = [
[[package]]
name = "parity-ui-precompiled"
version = "1.4.0"
source = "git+https://github.com/ethcore/js-precompiled.git#10a57a7df153360b4abeddff99e5b8f34a85ff53"
source = "git+https://github.com/ethcore/js-precompiled.git#f8bd7fa67e91daea3ac698ebcc447fae494802cb"
dependencies = [
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1246,7 +1260,7 @@ version = "0.2.8"
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.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1266,7 +1280,7 @@ version = "0.2.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.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1405,7 +1419,7 @@ name = "rand"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1459,7 +1473,7 @@ name = "rocksdb"
version = "0.4.5"
source = "git+https://github.com/ethcore/rust-rocksdb#64c63ccbe1f62c2e2b39262486f9ba813793af58"
dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)",
]
@ -1469,7 +1483,7 @@ version = "0.3.0"
source = "git+https://github.com/ethcore/rust-rocksdb#64c63ccbe1f62c2e2b39262486f9ba813793af58"
dependencies = [
"gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1489,7 +1503,7 @@ 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.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1500,7 +1514,7 @@ version = "0.2.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1671,7 +1685,7 @@ name = "syntex_errors"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex_pos 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1693,7 +1707,7 @@ version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1706,7 +1720,7 @@ version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex_errors 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1747,7 +1761,7 @@ name = "termios"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1756,7 +1770,7 @@ version = "2.0.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.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1773,7 +1787,7 @@ version = "0.1.35"
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.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -2012,7 +2026,7 @@ dependencies = [
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
"checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"
"checksum lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce12306c4739d86ee97c23139f3a34ddf0387bbf181bc7929d287025a8c3ef6b"
"checksum libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "23e3757828fa702a20072c37ff47938e9dd331b92fac6e223d26d4b7a55f7ee2"
"checksum libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "408014cace30ee0f767b1c4517980646a573ec61a57957aeeabcac8ac0a02e8d"
"checksum linked-hash-map 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bda158e0dabeb97ee8a401f4d17e479d6b891a14de0bba79d5cc2d4d325b5e48"
"checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd"
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
@ -2024,8 +2038,8 @@ dependencies = [
"checksum miniz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1f4d337a01c32e1f2122510fed46393d53ca35a7f429cb0450abaedfa3ed54"
"checksum mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)" = "<none>"
"checksum mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a637d1ca14eacae06296a008fa7ad955347e34efcb5891cfd8ba05491a37907e"
"checksum mio 0.6.0 (git+https://github.com/carllerche/mio)" = "<none>"
"checksum mio 0.6.0-dev (git+https://github.com/ethcore/mio?branch=timer-fix)" = "<none>"
"checksum mio 0.6.1 (git+https://github.com/carllerche/mio)" = "<none>"
"checksum miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d5bfc6782530ac8ace97af10a540054a37126b63b0702ddaaa243b73b5745b9a"
"checksum msdos_time 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c04b68cc63a8480fb2550343695f7be72effdec953a9d4508161c3e69041c7d8"
"checksum nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)" = "<none>"
@ -2033,6 +2047,7 @@ dependencies = [
"checksum net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)" = "6a816012ca11cb47009693c1e0c6130e26d39e4d97ee2a13c50e868ec83e3204"
"checksum nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f05c2fc965fc1cd6b73fa57fa7b89f288178737f2f3ce9e63e4a6a141189000e"
"checksum nix 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a7bb1da2be7da3cbffda73fc681d509ffd9e665af478d2bee1907cee0bc64b2"
"checksum nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0d95c5fa8b641c10ad0b8887454ebaafa3c92b5cd5350f8fc693adafd178e7b"
"checksum nodrop 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4d9a22dbcebdeef7bf275cbf444d6521d4e7a2fee187b72d80dba0817120dd8f"
"checksum nom 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6caab12c5f97aa316cb249725aa32115118e1522b445e26c257dd77cad5ffd4e"
"checksum num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "c04bd954dbf96f76bab6e5bd6cef6f1ce1262d15268ce4f926d2b5b778fa7af2"

View File

@ -38,6 +38,8 @@ after_test:
- cargo build --verbose --release
- ps: if($env:cert) { Start-FileDownload $env:cert -FileName $env:keyfile }
- ps: if($env:cert) { signtool sign /f $env:keyfile /p $env:certpass target\release\parity.exe }
- msbuild windows\ptray\ptray.vcxproj /p:Platform=x86 /p:Configuration=Release
- ps: if($env:cert) { signtool sign /f $env:keyfile /p $env:certpass windows\ptray\release\ptray.exe }
- makensis.exe nsis\installer.nsi
- ps: if($env:cert) { signtool sign /f $env:keyfile /p $env:certpass nsis\installer.exe }

View File

@ -24,6 +24,7 @@ ethabi = "0.2.2"
linked-hash-map = "0.3"
parity-dapps-glue = "1.4"
mime = "0.2"
time = "0.1.35"
serde_macros = { version = "0.8", optional = true }
zip = { version = "0.1", default-features = false }
ethcore-devtools = { path = "../devtools" }

View File

@ -32,14 +32,15 @@ use random_filename;
use SyncStatus;
use util::{Mutex, H256};
use util::sha3::sha3;
use page::LocalPageEndpoint;
use page::{LocalPageEndpoint, PageCache};
use handlers::{ContentHandler, ContentFetcherHandler, ContentValidator};
use endpoint::{Endpoint, EndpointPath, Handler};
use apps::cache::{ContentCache, ContentStatus};
use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest, serialize_manifest, Manifest};
use apps::urlhint::{URLHintContract, URLHint, URLHintResult};
const MAX_CACHED_DAPPS: usize = 10;
/// Limit of cached dapps/content
const MAX_CACHED_DAPPS: usize = 20;
pub struct ContentFetcher<R: URLHint = URLHintContract> {
dapps_path: PathBuf,
@ -71,12 +72,13 @@ impl<R: URLHint> ContentFetcher<R> {
}
}
fn still_syncing() -> Box<Handler> {
fn still_syncing(port: Option<u16>) -> Box<Handler> {
Box::new(ContentHandler::error(
StatusCode::ServiceUnavailable,
"Sync In Progress",
"Your node is still syncing. We cannot resolve any content before it's fully synced.",
Some("<a href=\"javascript:window.location.reload()\">Refresh</a>")
Some("<a href=\"javascript:window.location.reload()\">Refresh</a>"),
port,
))
}
@ -143,19 +145,19 @@ impl<R: URLHint> ContentFetcher<R> {
match content {
// Don't serve dapps if we are still syncing (but serve content)
Some(URLHintResult::Dapp(_)) if self.sync.is_major_importing() => {
(None, Self::still_syncing())
(None, Self::still_syncing(self.embeddable_at))
},
Some(URLHintResult::Dapp(dapp)) => {
let (handler, fetch_control) = ContentFetcherHandler::new(
dapp.url(),
control,
path.using_dapps_domains,
DappInstaller {
id: content_id.clone(),
dapps_path: self.dapps_path.clone(),
on_done: Box::new(on_done),
embeddable_at: self.embeddable_at,
}
},
self.embeddable_at,
);
(Some(ContentStatus::Fetching(fetch_control)), Box::new(handler) as Box<Handler>)
@ -164,19 +166,19 @@ impl<R: URLHint> ContentFetcher<R> {
let (handler, fetch_control) = ContentFetcherHandler::new(
content.url,
control,
path.using_dapps_domains,
ContentInstaller {
id: content_id.clone(),
mime: content.mime,
content_path: self.dapps_path.clone(),
on_done: Box::new(on_done),
}
},
self.embeddable_at,
);
(Some(ContentStatus::Fetching(fetch_control)), Box::new(handler) as Box<Handler>)
},
None if self.sync.is_major_importing() => {
(None, Self::still_syncing())
(None, Self::still_syncing(self.embeddable_at))
},
None => {
// This may happen when sync status changes in between
@ -185,7 +187,8 @@ impl<R: URLHint> ContentFetcher<R> {
StatusCode::NotFound,
"Resource Not Found",
"Requested resource was not found.",
None
None,
self.embeddable_at,
)) as Box<Handler>)
},
}
@ -255,6 +258,17 @@ impl ContentValidator for ContentInstaller {
// Create dir
try!(fs::create_dir_all(&self.content_path));
// Validate hash
let mut file_reader = io::BufReader::new(try!(fs::File::open(&path)));
let hash = try!(sha3(&mut file_reader));
let id = try!(self.id.as_str().parse().map_err(|_| ValidationError::InvalidContentId));
if id != hash {
return Err(ValidationError::HashMismatch {
expected: id,
got: hash,
});
}
// And prepare path for a file
let filename = path.file_name().expect("We always fetch a file.");
let mut content_path = self.content_path.clone();
@ -266,7 +280,7 @@ impl ContentValidator for ContentInstaller {
try!(fs::copy(&path, &content_path));
Ok((self.id.clone(), LocalPageEndpoint::single_file(content_path, self.mime.clone())))
Ok((self.id.clone(), LocalPageEndpoint::single_file(content_path, self.mime.clone(), PageCache::Enabled)))
}
fn done(&self, endpoint: Option<LocalPageEndpoint>) {
@ -372,7 +386,7 @@ impl ContentValidator for DappInstaller {
try!(manifest_file.write_all(manifest_str.as_bytes()));
// Create endpoint
let app = LocalPageEndpoint::new(target, manifest.clone().into(), self.embeddable_at);
let app = LocalPageEndpoint::new(target, manifest.clone().into(), PageCache::Enabled, self.embeddable_at);
// Return modified app manifest
Ok((manifest.id.clone(), app))
@ -412,7 +426,7 @@ mod tests {
version: "".into(),
author: "".into(),
icon_url: "".into(),
}, None);
}, Default::default(), None);
// when
fetcher.set_status("test", ContentStatus::Ready(handler));

View File

@ -18,7 +18,7 @@ use std::io;
use std::io::Read;
use std::fs;
use std::path::PathBuf;
use page::LocalPageEndpoint;
use page::{LocalPageEndpoint, PageCache};
use endpoint::{Endpoints, EndpointInfo};
use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest};
@ -102,7 +102,7 @@ pub fn local_endpoints(dapps_path: String, signer_port: Option<u16>) -> Endpoint
for dapp in local_dapps(dapps_path) {
pages.insert(
dapp.id,
Box::new(LocalPageEndpoint::new(dapp.path, dapp.info, signer_port))
Box::new(LocalPageEndpoint::new(dapp.path, dapp.info, PageCache::Disabled, signer_port))
);
}
pages

View File

@ -33,14 +33,6 @@ pub const RPC_PATH : &'static str = "rpc";
pub const API_PATH : &'static str = "api";
pub const UTILS_PATH : &'static str = "parity-utils";
pub fn redirection_address(using_dapps_domains: bool, app_id: &str) -> String {
if using_dapps_domains {
format!("http://{}{}/", app_id, DAPPS_DOMAIN)
} else {
format!("/{}/", app_id)
}
}
pub fn utils() -> Box<Endpoint> {
Box::new(PageEndpoint::with_prefix(parity_ui::App::default(), UTILS_PATH.to_owned()))
}

View File

@ -48,11 +48,7 @@ impl ContentHandler {
Self::new_embeddable(code, content, mime!(Text/Html), embeddable_at)
}
pub fn error(code: StatusCode, title: &str, message: &str, details: Option<&str>) -> Self {
Self::error_embeddable(code, title, message, details, None)
}
pub fn error_embeddable(code: StatusCode, title: &str, message: &str, details: Option<&str>, embeddable_at: Option<u16>) -> Self {
pub fn error(code: StatusCode, title: &str, message: &str, details: Option<&str>, embeddable_at: Option<u16>) -> Self {
Self::html(code, format!(
include_str!("../error_tpl.html"),
title=title,

View File

@ -22,14 +22,14 @@ use std::sync::{mpsc, Arc};
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::{Instant, Duration};
use util::Mutex;
use url::Url;
use fetch::{Client, Fetch, FetchResult};
use hyper::{server, Decoder, Encoder, Next, Method, Control};
use hyper::net::HttpStream;
use hyper::status::StatusCode;
use handlers::{ContentHandler, Redirection};
use apps::redirection_address;
use handlers::{ContentHandler, Redirection, extract_url};
use page::LocalPageEndpoint;
const FETCH_TIMEOUT: u64 = 30;
@ -136,8 +136,9 @@ pub struct ContentFetcherHandler<H: ContentValidator> {
control: Option<Control>,
status: FetchState,
client: Option<Client>,
using_dapps_domains: bool,
installer: H,
request_url: Option<Url>,
embeddable_at: Option<u16>,
}
impl<H: ContentValidator> Drop for ContentFetcherHandler<H> {
@ -155,8 +156,9 @@ impl<H: ContentValidator> ContentFetcherHandler<H> {
pub fn new(
url: String,
control: Control,
using_dapps_domains: bool,
handler: H) -> (Self, Arc<FetchControl>) {
handler: H,
embeddable_at: Option<u16>,
) -> (Self, Arc<FetchControl>) {
let fetch_control = Arc::new(FetchControl::default());
let client = Client::default();
@ -165,8 +167,9 @@ impl<H: ContentValidator> ContentFetcherHandler<H> {
control: Some(control),
client: Some(client),
status: FetchState::NotStarted(url),
using_dapps_domains: using_dapps_domains,
installer: handler,
request_url: None,
embeddable_at: embeddable_at,
};
(handler, fetch_control)
@ -189,6 +192,7 @@ impl<H: ContentValidator> ContentFetcherHandler<H> {
impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<H> {
fn on_request(&mut self, request: server::Request<HttpStream>) -> Next {
self.request_url = extract_url(&request);
let status = if let FetchState::NotStarted(ref url) = self.status {
Some(match *request.method() {
// Start fetching content
@ -204,6 +208,7 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<
"Unable To Start Dapp Download",
"Could not initialize download of the dapp. It might be a problem with the remote server.",
Some(&format!("{}", e)),
self.embeddable_at,
)),
}
},
@ -213,6 +218,7 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<
"Method Not Allowed",
"Only <code>GET</code> requests are allowed.",
None,
self.embeddable_at,
)),
})
} else { None };
@ -234,7 +240,8 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<
StatusCode::GatewayTimeout,
"Download Timeout",
&format!("Could not fetch content within {} seconds.", FETCH_TIMEOUT),
None
None,
self.embeddable_at,
);
Self::close_client(&mut self.client);
(Some(FetchState::Error(timeout)), Next::write())
@ -255,12 +262,15 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<
StatusCode::BadGateway,
"Invalid Dapp",
"Downloaded bundle does not contain a valid content.",
Some(&format!("{:?}", e))
Some(&format!("{:?}", e)),
self.embeddable_at,
))
},
Ok((id, result)) => {
let address = redirection_address(self.using_dapps_domains, &id);
FetchState::Done(id, result, Redirection::new(&address))
let url: String = self.request_url.take()
.map(|url| url.raw.into_string())
.expect("Request URL always read in on_request; qed");
FetchState::Done(id, result, Redirection::new(&url))
},
};
// Remove temporary zip file
@ -274,6 +284,7 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<
"Download Error",
"There was an error when fetching the content.",
Some(&format!("{:?}", e)),
self.embeddable_at,
);
(Some(FetchState::Error(error)), Next::write())
},

View File

@ -44,6 +44,7 @@
#![cfg_attr(feature="nightly", plugin(clippy))]
extern crate hyper;
extern crate time;
extern crate url as url_lib;
extern crate unicase;
extern crate serde;

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/>.
use page::handler;
use page::{handler, PageCache};
use std::sync::Arc;
use endpoint::{Endpoint, EndpointInfo, EndpointPath, Handler};
use parity_dapps::{WebApp, File, Info};
@ -80,6 +80,7 @@ impl<T: WebApp> Endpoint for PageEndpoint<T> {
prefix: self.prefix.clone(),
path: path,
file: handler::ServedFile::new(self.safe_to_embed_at_port.clone()),
cache: PageCache::Disabled,
safe_to_embed_at_port: self.safe_to_embed_at_port.clone(),
})
}

View File

@ -15,6 +15,8 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::io::Write;
use time::{self, Duration};
use hyper::header;
use hyper::server;
use hyper::uri::RequestUri;
@ -59,7 +61,7 @@ pub enum ServedFile<T: Dapp> {
impl<T: Dapp> ServedFile<T> {
pub fn new(embeddable_at: Option<u16>) -> Self {
ServedFile::Error(ContentHandler::error_embeddable(
ServedFile::Error(ContentHandler::error(
StatusCode::NotFound,
"404 Not Found",
"Requested dapp resource was not found.",
@ -69,6 +71,19 @@ impl<T: Dapp> ServedFile<T> {
}
}
/// Defines what cache headers should be appended to returned resources.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum PageCache {
Enabled,
Disabled,
}
impl Default for PageCache {
fn default() -> Self {
PageCache::Disabled
}
}
/// A handler for a single webapp.
/// Resolves correct paths and serves as a plumbing code between
/// hyper server and dapp.
@ -83,6 +98,8 @@ pub struct PageHandler<T: Dapp> {
pub path: EndpointPath,
/// Flag indicating if the file can be safely embeded (put in iframe).
pub safe_to_embed_at_port: Option<u16>,
/// Cache settings for this page.
pub cache: PageCache,
}
impl<T: Dapp> PageHandler<T> {
@ -129,9 +146,19 @@ impl<T: Dapp> server::Handler<HttpStream> for PageHandler<T> {
ServedFile::File(ref f) => {
res.set_status(StatusCode::Ok);
if let PageCache::Enabled = self.cache {
let mut headers = res.headers_mut();
let validity = Duration::days(365);
headers.set(header::CacheControl(vec![
header::CacheDirective::Public,
header::CacheDirective::MaxAge(validity.num_seconds() as u32),
]));
headers.set(header::Expires(header::HttpDate(time::now() + validity)));
}
match f.content_type().parse() {
Ok(mime) => res.headers_mut().set(header::ContentType(mime)),
Err(()) => debug!(target: "page_handler", "invalid MIME type: {}", f.content_type()),
Err(()) => debug!(target: "dapps", "invalid MIME type: {}", f.content_type()),
}
// Security headers:
@ -218,6 +245,7 @@ fn should_extract_path_with_appid() {
using_dapps_domains: true,
},
file: ServedFile::new(None),
cache: Default::default(),
safe_to_embed_at_port: None,
};

View File

@ -18,7 +18,7 @@ use mime_guess;
use std::io::{Seek, Read, SeekFrom};
use std::fs;
use std::path::{Path, PathBuf};
use page::handler;
use page::handler::{self, PageCache};
use endpoint::{Endpoint, EndpointInfo, EndpointPath, Handler};
#[derive(Debug, Clone)]
@ -26,24 +26,27 @@ pub struct LocalPageEndpoint {
path: PathBuf,
mime: Option<String>,
info: Option<EndpointInfo>,
cache: PageCache,
embeddable_at: Option<u16>,
}
impl LocalPageEndpoint {
pub fn new(path: PathBuf, info: EndpointInfo, embeddable_at: Option<u16>) -> Self {
pub fn new(path: PathBuf, info: EndpointInfo, cache: PageCache, embeddable_at: Option<u16>) -> Self {
LocalPageEndpoint {
path: path,
mime: None,
info: Some(info),
cache: cache,
embeddable_at: embeddable_at,
}
}
pub fn single_file(path: PathBuf, mime: String) -> Self {
pub fn single_file(path: PathBuf, mime: String, cache: PageCache) -> Self {
LocalPageEndpoint {
path: path,
mime: Some(mime),
info: None,
cache: cache,
embeddable_at: None,
}
}
@ -66,6 +69,7 @@ impl Endpoint for LocalPageEndpoint {
path: path,
file: handler::ServedFile::new(None),
safe_to_embed_at_port: self.embeddable_at,
cache: self.cache,
})
} else {
Box::new(handler::PageHandler {
@ -74,6 +78,7 @@ impl Endpoint for LocalPageEndpoint {
path: path,
file: handler::ServedFile::new(None),
safe_to_embed_at_port: self.embeddable_at,
cache: self.cache,
})
}
}

View File

@ -21,4 +21,5 @@ mod handler;
pub use self::local::LocalPageEndpoint;
pub use self::builtin::PageEndpoint;
pub use self::handler::PageCache;

View File

@ -59,7 +59,8 @@ impl Authorization for HttpBasicAuth {
status::StatusCode::Unauthorized,
"Unauthorized",
"You need to provide valid credentials to access this page.",
None
None,
None,
)))
},
Access::AuthRequired => {

View File

@ -41,6 +41,7 @@ pub fn host_invalid_response() -> Box<server::Handler<HttpStream> + Send> {
Box::new(ContentHandler::error(StatusCode::Forbidden,
"Current Host Is Disallowed",
"You are trying to access your node using incorrect address.",
Some("Use allowed URL or specify different <code>hosts</code> CLI options.")
Some("Use allowed URL or specify different <code>hosts</code> CLI options."),
None,
))
}

View File

@ -117,6 +117,7 @@ impl<A: Authorization + 'static> server::Handler<HttpStream> for Router<A> {
"404 Not Found",
"Requested content was not found.",
None,
self.signer_port,
))
},
// Redirect any other GET request to signer.
@ -131,6 +132,7 @@ impl<A: Authorization + 'static> server::Handler<HttpStream> for Router<A> {
"404 Not Found",
"Your homepage is not available when Trusted Signer is disabled.",
Some("You can still access dapps by writing a correct address, though. Re-enabled Signer to get your homepage back."),
self.signer_port,
))
}
},

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/>.
use tests::helpers::{serve_with_registrar, serve_with_registrar_and_sync, request, assert_security_headers};
use tests::helpers::{serve_with_registrar, serve_with_registrar_and_sync, request, assert_security_headers_for_embed};
#[test]
fn should_resolve_dapp() {
@ -34,7 +34,7 @@ fn should_resolve_dapp() {
// then
assert_eq!(response.status, "HTTP/1.1 404 Not Found".to_owned());
assert_eq!(registrar.calls.lock().len(), 2);
assert_security_headers(&response.headers);
assert_security_headers_for_embed(&response.headers);
}
#[test]
@ -63,5 +63,5 @@ fn should_return_503_when_syncing_but_should_make_the_calls() {
// then
assert_eq!(response.status, "HTTP/1.1 503 Service Unavailable".to_owned());
assert_eq!(registrar.calls.lock().len(), 4);
assert_security_headers(&response.headers);
assert_security_headers_for_embed(&response.headers);
}

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/>.
use tests::helpers::{serve, request, assert_security_headers};
use tests::helpers::{serve, request, assert_security_headers, assert_security_headers_for_embed};
#[test]
fn should_redirect_to_home() {
@ -93,7 +93,7 @@ fn should_display_404_on_invalid_dapp() {
// then
assert_eq!(response.status, "HTTP/1.1 404 Not Found".to_owned());
assert_security_headers(&response.headers);
assert_security_headers_for_embed(&response.headers);
}
#[test]
@ -113,7 +113,7 @@ fn should_display_404_on_invalid_dapp_with_domain() {
// then
assert_eq!(response.status, "HTTP/1.1 404 Not Found".to_owned());
assert_security_headers(&response.headers);
assert_security_headers_for_embed(&response.headers);
}
#[test]

View File

@ -1,6 +1,6 @@
{
"name": "parity.js",
"version": "0.1.37",
"version": "0.1.47",
"main": "release/index.js",
"jsnext:main": "src/index.js",
"author": "Parity Team <admin@parity.io>",

View File

@ -58,6 +58,11 @@ export default class Ethcore {
.execute('ethcore_dropNonReservedPeers');
}
enode () {
return this._transport
.execute('ethcore_enode');
}
extraData () {
return this._transport
.execute('ethcore_extraData');

View File

@ -80,7 +80,9 @@ export default class RegisterAction extends Component {
modal={ sending || complete }
className={ styles.dialog }
onRequestClose={ this.onClose }
actions={ this.renderActions() } >
actions={ this.renderActions() }
autoScrollBodyContent
>
{ this.renderContent() }
</Dialog>
);

View File

@ -85,6 +85,15 @@ export default {
}
},
enode: {
desc: 'Returns the node enode URI',
params: [],
returns: {
type: String,
desc: 'Enode URI'
}
},
extraData: {
desc: 'Returns currently set extra data',
params: [],

View File

@ -136,6 +136,7 @@ export default class AddAddress extends Component {
api.personal.setAccountName(address, name),
api.personal.setAccountMeta(address, {
description,
timestamp: Date.now(),
deleted: false
})
]).catch((error) => {

View File

@ -145,6 +145,7 @@ export default class AddContract extends Component {
api.personal.setAccountMeta(address, {
contract: true,
deleted: false,
timestamp: Date.now(),
abi: abiParsed,
description
})

View File

@ -214,7 +214,10 @@ export default class CreateAccount extends Component {
this.setState({ address });
return api.personal
.setAccountName(address, this.state.name)
.then(() => api.personal.setAccountMeta(address, { passwordHint: this.state.passwordHint }));
.then(() => api.personal.setAccountMeta(address, {
timestamp: Date.now(),
passwordHint: this.state.passwordHint
}));
})
.then(() => {
this.onNext();
@ -236,7 +239,10 @@ export default class CreateAccount extends Component {
this.setState({ address });
return api.personal
.setAccountName(address, this.state.name)
.then(() => api.personal.setAccountMeta(address, { passwordHint: this.state.passwordHint }));
.then(() => api.personal.setAccountMeta(address, {
timestamp: Date.now(),
passwordHint: this.state.passwordHint
}));
})
.then(() => {
this.onNext();
@ -285,7 +291,10 @@ export default class CreateAccount extends Component {
return api.personal
.setAccountName(address, this.state.name)
.then(() => api.personal.setAccountMeta(address, { passwordHint: this.state.passwordHint }));
.then(() => api.personal.setAccountMeta(address, {
timestamp: Date.now(),
passwordHint: this.state.passwordHint
}));
})
.then(() => {
this.onNext();

View File

@ -216,6 +216,7 @@ export default class DeployContract extends Component {
api.personal.setAccountMeta(address, {
abi: abiParsed,
contract: true,
timestamp: Date.now(),
deleted: false,
description
})

View File

@ -19,7 +19,7 @@ import ActionDoneAll from 'material-ui/svg-icons/action/done-all';
import ContentClear from 'material-ui/svg-icons/content/clear';
import { BusyStep, CompletedStep, Button, IdentityIcon, Modal, TxHash } from '../../ui';
import { validateAddress } from '../../util/validation';
import { validateAddress, validateUint } from '../../util/validation';
import DetailsStep from './DetailsStep';
@ -41,6 +41,7 @@ export default class ExecuteContract extends Component {
state = {
amount: '0',
amountError: null,
fromAddressError: null,
func: null,
funcError: null,
values: [],
@ -77,7 +78,8 @@ export default class ExecuteContract extends Component {
renderDialogActions () {
const { onClose, fromAddress } = this.props;
const { sending, step } = this.state;
const { sending, step, fromAddressError, valuesError } = this.state;
const hasError = fromAddressError || valuesError.find((error) => error);
const cancelBtn = (
<Button
key='cancel'
@ -92,7 +94,7 @@ export default class ExecuteContract extends Component {
<Button
key='postTransaction'
label='post transaction'
disabled={ sending }
disabled={ sending || hasError }
icon={ <IdentityIcon address={ fromAddress } button /> }
onClick={ this.postTransaction } />
];
@ -177,12 +179,16 @@ export default class ExecuteContract extends Component {
let valueError = null;
switch (input.kind.type) {
case 'address':
valueError = validateAddress(_value).addressError;
break;
case 'bool':
value = _value === 'true';
break;
case 'address':
valueError = validateAddress(_value).addressError;
case 'uint':
valueError = validateUint(_value).valueError;
break;
}
@ -190,8 +196,8 @@ export default class ExecuteContract extends Component {
valuesError[index] = valueError;
this.setState({
values,
valuesError
values: [].concat(values),
valuesError: [].concat(valuesError)
});
}

View File

@ -29,6 +29,20 @@ export default class Status {
this._pollPing();
this._pollStatus();
this._pollLogs();
this._fetchEnode();
}
_fetchEnode () {
this._api
.ethcore.enode()
.then((enode) => {
this._store.dispatch(statusCollection({ enode }));
})
.catch(() => {
window.setTimeout(() => {
this._fetchEnode();
}, 1000);
});
}
_subscribeBlockNumber () {
@ -68,11 +82,17 @@ export default class Status {
_pollStatus = () => {
const { secureToken, isConnected, isConnecting, needsToken } = this._api;
const nextTimeout = (timeout = 1000) => {
setTimeout(this._pollStatus, timeout);
};
if (isConnected !== this._store.getState().nodeStatus.isConnected) {
this._fetchEnode();
}
this._store.dispatch(statusCollection({ isConnected, isConnecting, needsToken, secureToken }));
if (!isConnected) {
nextTimeout(250);
return;

View File

@ -25,6 +25,7 @@ const initialState = {
clientVersion: '',
coinbase: '',
defaultExtraData: '',
enode: '',
extraData: '',
gasFloorTarget: new BigNumber(0),
hashrate: new BigNumber(0),

View File

@ -27,14 +27,23 @@ import styles from './sort.css';
export default class ActionbarSort extends Component {
static propTypes = {
onChange: PropTypes.func.isRequired,
order: PropTypes.string
order: PropTypes.string,
showDefault: PropTypes.bool,
metas: PropTypes.array
};
static defaultProps = {
metas: [],
showDefault: true
}
state = {
menuOpen: false
}
render () {
const { showDefault } = this.props;
return (
<IconMenu
iconButtonElement={
@ -50,14 +59,56 @@ export default class ActionbarSort extends Component {
onItemTouchTap={ this.handleSortChange }
targetOrigin={ { horizontal: 'right', vertical: 'top' } }
anchorOrigin={ { horizontal: 'right', vertical: 'top' } }
>
<MenuItem value='' primaryText='Default' />
<MenuItem value='tags' primaryText='Sort by tags' />
<MenuItem value='name' primaryText='Sort by name' />
touchTapCloseDelay={ 0 }
>
{
showDefault
? this.renderMenuItem('', 'Default')
: null
}
{ this.renderMenuItem('tags', 'Sort by tags') }
{ this.renderMenuItem('name', 'Sort by name') }
{ this.renderMenuItem('eth', 'Sort by ETH') }
{ this.renderSortByMetas() }
</IconMenu>
);
}
renderSortByMetas () {
const { metas } = this.props;
return metas
.map((meta, index) => {
return this
.renderMenuItem(meta.key, `Sort by ${meta.label}`, index);
});
}
renderMenuItem (value, label, key = null) {
const { order } = this.props;
const props = {};
if (key !== null) {
props.key = key;
}
const checked = order === value;
return (
<MenuItem
checked={ checked }
value={ value }
primaryText={ label }
innerDivStyle={ {
paddingLeft: checked ? 50 : 16
} }
{ ...props }
/>
);
}
handleSortChange = (event, child) => {
const order = child.props.value;
this.props.onChange(order);

View File

@ -18,6 +18,7 @@
flex: 1;
padding: 0em;
background: rgba(0, 0, 0, 0.8);
height: 100%;
}
.compact,

View File

@ -16,6 +16,7 @@
import React, { Component, PropTypes } from 'react';
import { MenuItem } from 'material-ui';
import { isEqual } from 'lodash';
import AutoComplete from '../AutoComplete';
import IdentityIcon from '../../IdentityIcon';
@ -24,57 +25,82 @@ import IdentityName from '../../IdentityName';
import styles from './addressSelect.css';
export default class AddressSelect extends Component {
static contextTypes = {
api: PropTypes.object.isRequired
}
static propTypes = {
disabled: PropTypes.bool,
accounts: PropTypes.object,
contacts: PropTypes.object,
contracts: PropTypes.object,
label: PropTypes.string,
hint: PropTypes.string,
error: PropTypes.string,
value: PropTypes.string,
tokens: PropTypes.object,
onChange: PropTypes.func.isRequired
onChange: PropTypes.func.isRequired,
allowInput: PropTypes.bool
}
state = {
entries: {},
addresses: [],
value: ''
}
entriesFromProps (props = this.props) {
const { accounts, contacts, contracts } = props;
const entries = Object.assign({}, accounts || {}, contacts || {}, contracts || {});
return entries;
}
componentWillMount () {
const { accounts, contacts, value } = this.props;
const entries = Object.assign({}, accounts || {}, contacts || {});
this.setState({ entries, value });
const { value } = this.props;
const entries = this.entriesFromProps();
const addresses = Object.keys(entries).sort();
this.setState({ entries, addresses, value });
}
componentWillReceiveProps (newProps) {
const { accounts, contacts } = newProps;
const entries = Object.assign({}, accounts || {}, contacts || {});
this.setState({ entries });
const entries = this.entriesFromProps();
const addresses = Object.keys(entries).sort();
if (!isEqual(addresses, this.state.addresses)) {
this.setState({ entries, addresses });
}
if (newProps.value !== this.props.value) {
this.setState({ value: newProps.value });
}
}
render () {
const { disabled, error, hint, label } = this.props;
const { entries } = this.state;
const value = this.getSearchText();
const { allowInput, disabled, error, hint, label } = this.props;
const { entries, value } = this.state;
const searchText = this.getSearchText();
const icon = this.renderIdentityIcon(value);
return (
<div className={ styles.container }>
<AutoComplete
className={ (error || !value) ? '' : styles.paddedInput }
className={ !icon ? '' : styles.paddedInput }
disabled={ disabled }
label={ label }
hint={ hint ? `search for ${hint}` : 'search for an address' }
error={ error }
onChange={ this.onChange }
value={ value }
onBlur={ this.onBlur }
onUpdateInput={ allowInput && this.onUpdateInput }
value={ searchText }
filter={ this.handleFilter }
entries={ entries }
entry={ this.getEntry() || {} }
renderItem={ this.renderItem }
/>
{ this.renderIdentityIcon(value) }
{ icon }
</div>
);
}
@ -82,7 +108,7 @@ export default class AddressSelect extends Component {
renderIdentityIcon (inputValue) {
const { error, value } = this.props;
if (error || !inputValue) {
if (error || !inputValue || value.length !== 42) {
return null;
}
@ -96,8 +122,9 @@ export default class AddressSelect extends Component {
renderItem = (entry) => {
return {
text: entry.address,
value: this.renderSelectEntry(entry)
text: entry.name && entry.name.toUpperCase() || entry.address,
value: this.renderSelectEntry(entry),
address: entry.address
};
}
@ -127,32 +154,48 @@ export default class AddressSelect extends Component {
getSearchText () {
const entry = this.getEntry();
if (!entry) return '';
const { value } = this.state;
return entry.name ? entry.name.toUpperCase() : '';
return entry && entry.name
? entry.name.toUpperCase()
: value;
}
getEntry () {
const { value } = this.props;
if (!value) return '';
const { entries } = this.state;
return entries[value];
const { entries, value } = this.state;
return value ? entries[value] : null;
}
handleFilter = (searchText, address) => {
handleFilter = (searchText, name, item) => {
const { address } = item;
const entry = this.state.entries[address];
const lowCaseSearch = searchText.toLowerCase();
return [ entry.name, entry.address ]
return [entry.name, entry.address]
.some(text => text.toLowerCase().indexOf(lowCaseSearch) !== -1);
}
onChange = (entry, empty) => {
const { allowInput } = this.props;
const { value } = this.state;
const address = entry && entry.address
? entry.address
: (empty ? '' : this.state.value);
: ((empty && !allowInput) ? '' : value);
this.props.onChange(null, address);
}
onUpdateInput = (query, choices) => {
const { api } = this.context;
const address = query.trim();
if (!/^0x/.test(address) && api.util.isAddressValid(`0x${address}`)) {
const checksumed = api.util.toChecksumAddress(`0x${address}`);
return this.props.onChange(null, checksumed);
}
this.props.onChange(null, address);
};
}

View File

@ -21,6 +21,7 @@ import { PopoverAnimationVertical } from 'material-ui/Popover';
export default class AutoComplete extends Component {
static propTypes = {
onChange: PropTypes.func.isRequired,
onUpdateInput: PropTypes.func,
disabled: PropTypes.bool,
label: PropTypes.string,
hint: PropTypes.string,
@ -43,7 +44,7 @@ export default class AutoComplete extends Component {
}
render () {
const { disabled, error, hint, label, value, className, filter } = this.props;
const { disabled, error, hint, label, value, className, filter, onUpdateInput } = this.props;
const { open } = this.state;
return (
@ -54,11 +55,11 @@ export default class AutoComplete extends Component {
hintText={ hint }
errorText={ error }
onNewRequest={ this.onChange }
onUpdateInput={ onUpdateInput }
searchText={ value }
onFocus={ this.onFocus }
onBlur={ this.onBlur }
animation={ PopoverAnimationVertical }
filter={ filter }
popoverProps={ { open } }
openOnFocus
@ -108,11 +109,17 @@ export default class AutoComplete extends Component {
}
onBlur = () => {
window.setTimeout(() => {
const { entry } = this.state;
const { onUpdateInput } = this.props;
this.handleOnChange(entry);
}, 100);
// TODO: Handle blur gracefully where we use onUpdateInput (currently replaces input
// input where text is allowed with the last selected value from the dropdown)
if (!onUpdateInput) {
window.setTimeout(() => {
const { entry } = this.state;
this.handleOnChange(entry);
}, 100);
}
}
onFocus = () => {
@ -131,5 +138,4 @@ export default class AutoComplete extends Component {
this.props.onChange(value, empty);
}
}
}

View File

@ -26,8 +26,16 @@
padding-left: 0 !important;
}
.icon {
.icon,
.iconDisabled {
position: absolute;
top: 35px;
}
.icon {
left: 0;
}
.iconDisabled {
left: 24px;
}

View File

@ -69,14 +69,14 @@ class InputAddress extends Component {
}
renderIcon () {
const { value } = this.props;
const { value, disabled } = this.props;
if (!value || !value.length || !util.isAddressValid(value)) {
return null;
}
return (
<div className={ styles.icon }>
<div className={ disabled ? styles.iconDisabled : styles.icon }>
<IdentityIcon
inline center
address={ value } />

View File

@ -1,31 +0,0 @@
/* Copyright 2015, 2016 Ethcore (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/>.
*/
.inputselect {
position: relative;
}
.inputselect svg {
padding-right: 84px;
}
.toggle {
position: absolute !important;
top: 38px;
right: 0;
display: inline-block !important;
width: auto !important;
}

View File

@ -17,103 +17,46 @@
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Toggle } from 'material-ui';
import AddressSelect from '../AddressSelect';
import InputAddress from '../InputAddress';
import styles from './inputAddressSelect.css';
class InputAddressSelect extends Component {
static propTypes = {
accounts: PropTypes.object,
contacts: PropTypes.object,
disabled: PropTypes.bool,
editing: PropTypes.bool,
accounts: PropTypes.object.isRequired,
contacts: PropTypes.object.isRequired,
contracts: PropTypes.object.isRequired,
error: PropTypes.string,
label: PropTypes.string,
hint: PropTypes.string,
value: PropTypes.string,
tokens: PropTypes.object,
onChange: PropTypes.func
};
state = {
editing: this.props.editing || false,
entries: []
}
render () {
const { editing } = this.state;
return (
<div className={ styles.inputselect }>
{ editing ? this.renderInput() : this.renderSelect() }
<Toggle
className={ styles.toggle }
label='Edit'
labelPosition='right'
toggled={ editing }
onToggle={ this.onToggle } />
</div>
);
}
renderInput () {
const { disabled, error, hint, label, value, tokens } = this.props;
return (
<InputAddress
disabled={ disabled }
error={ error }
hint={ hint }
label={ label }
value={ value }
tokens={ tokens }
onChange={ this.onChangeInput } />
);
}
renderSelect () {
const { accounts, contacts, disabled, error, hint, label, value, tokens } = this.props;
const { accounts, contacts, contracts, label, hint, error, value, onChange } = this.props;
return (
<AddressSelect
allowInput
accounts={ accounts }
contacts={ contacts }
disabled={ disabled }
contracts={ contracts }
error={ error }
label={ label }
hint={ hint }
error={ error }
value={ value }
tokens={ tokens }
onChange={ this.onChangeSelect } />
onChange={ onChange } />
);
}
onToggle = () => {
const { editing } = this.state;
this.setState({
editing: !editing
});
}
onChangeInput = (event, value) => {
this.props.onChange(event, value);
}
onChangeSelect = (event, value) => {
this.props.onChange(event, value);
}
}
function mapStateToProps (state) {
const { accounts, contacts } = state.personal;
const { accounts, contacts, contracts } = state.personal;
return {
accounts,
contacts
contacts,
contracts
};
}

View File

@ -14,6 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import BigNumber from 'bignumber.js';
import util from '../api/util';
export const ERRORS = {
@ -22,7 +24,10 @@ export const ERRORS = {
invalidChecksum: 'address has failed the checksum formatting',
invalidName: 'name should not be blank and longer than 2',
invalidAbi: 'abi should be a valid JSON array',
invalidCode: 'code should be the compiled hex string'
invalidCode: 'code should be the compiled hex string',
invalidNumber: 'invalid number format',
negativeNumber: 'input number should be positive',
decimalNumber: 'input number should not contain decimals'
};
export function validateAbi (abi, api) {
@ -88,3 +93,23 @@ export function validateName (name) {
nameError
};
}
export function validateUint (value) {
let valueError = null;
try {
const bn = new BigNumber(value);
if (bn.lt(0)) {
valueError = ERRORS.negativeNumber;
} else if (bn.toString().indexOf('.') !== -1) {
valueError = ERRORS.decimalNumber;
}
} catch (e) {
valueError = ERRORS.invalidNumber;
}
return {
value,
valueError
};
}

View File

@ -29,6 +29,7 @@ export default class List extends Component {
search: PropTypes.array,
empty: PropTypes.bool,
order: PropTypes.string,
orderFallback: PropTypes.string,
handleAddSearchToken: PropTypes.func
};
@ -79,9 +80,9 @@ export default class List extends Component {
}
sortAddresses (addresses) {
const { order } = this.props;
const { order, orderFallback } = this.props;
if (!order || ['tags', 'name'].indexOf(order) === -1) {
if (!order) {
return addresses;
}
@ -91,26 +92,77 @@ export default class List extends Component {
const accountA = accounts[addressA];
const accountB = accounts[addressB];
if (order === 'name') {
return accountA.name.localeCompare(accountB.name);
const sort = this.compareAccounts(accountA, accountB, order);
if (sort === 0 && orderFallback) {
return this.compareAccounts(accountA, accountB, orderFallback);
}
if (order === 'tags') {
const tagsA = [].concat(accountA.meta.tags)
.filter(t => t)
.sort();
const tagsB = [].concat(accountB.meta.tags)
.filter(t => t)
.sort();
if (tagsA.length === 0) return 1;
if (tagsB.length === 0) return -1;
return tagsA.join('').localeCompare(tagsB.join(''));
}
return sort;
});
}
compareAccounts (accountA, accountB, key) {
if (key === 'name') {
return accountA.name.localeCompare(accountB.name);
}
if (key === 'eth') {
const { balances } = this.props;
const balanceA = balances[accountA.address];
const balanceB = balances[accountB.address];
if (!balanceA && !balanceB) return 0;
if (balanceA && !balanceB) return -1;
if (!balanceA && balanceB) return 1;
const ethA = balanceA.tokens
.find(token => token.token.tag.toLowerCase() === 'eth')
.value;
const ethB = balanceB.tokens
.find(token => token.token.tag.toLowerCase() === 'eth')
.value;
return -1 * ethA.comparedTo(ethB);
}
if (key === 'tags') {
const tagsA = [].concat(accountA.meta.tags)
.filter(t => t)
.sort()
.join('');
const tagsB = [].concat(accountB.meta.tags)
.filter(t => t)
.sort()
.join('');
if (!tagsA && !tagsB) return 0;
if (tagsA && !tagsB) return -1;
if (!tagsA && tagsB) return 1;
return tagsA.localeCompare(tagsB);
}
const metaA = accountA.meta[key];
const metaB = accountB.meta[key];
if (!metaA && !metaB) {
return 0;
}
if ((metaA && !metaB) || (metaA < metaB)) {
return -1;
}
if ((!metaA && metaB) || (metaA > metaB)) {
return 1;
}
return 0;
}
getFilteredAddresses () {
const { accounts, search } = this.props;
const searchValues = (search || []).map(v => v.toLowerCase());

View File

@ -15,16 +15,24 @@
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.status {
clear: both;
padding: 1.5em;
text-align: right;
color: #ddd;
display: flex;
flex-direction: column;
align-items: flex-end;
}
.title {
margin: 0 0.5em 0 2em;
}
.enode {
width: 45em;
word-wrap: break-word;
margin: 0.5em 0 0.25em;
}
.block {
}

View File

@ -26,6 +26,7 @@ class Status extends Component {
static propTypes = {
blockNumber: PropTypes.object.isRequired,
clientVersion: PropTypes.string,
enode: PropTypes.string,
netPeers: PropTypes.object,
netChain: PropTypes.string,
isTest: PropTypes.bool
@ -44,6 +45,7 @@ class Status extends Component {
<div className={ styles.version }>
{ clientVersion }
</div>
{ this.renderEnode() }
<div className={ styles.netinfo }>
<div>
<BlockStatus />
@ -58,14 +60,29 @@ class Status extends Component {
</div>
);
}
renderEnode () {
const { enode } = this.props;
if (!enode) {
return null;
}
return (
<div className={ styles.enode }>
{ enode }
</div>
);
}
}
function mapStateToProps (state) {
const { blockNumber, clientVersion, netPeers, netChain, isTest } = state.nodeStatus;
const { blockNumber, clientVersion, enode, netPeers, netChain, isTest } = state.nodeStatus;
return {
blockNumber,
clientVersion,
enode,
netPeers,
netChain,
isTest

View File

@ -19,7 +19,7 @@ import React, { Component, PropTypes } from 'react';
import LinearProgress from 'material-ui/LinearProgress';
import { Card, CardActions, CardTitle, CardText } from 'material-ui/Card';
import { Button, Input } from '../../../ui';
import { Button, Input, InputAddressSelect } from '../../../ui';
import styles from './queries.css';
@ -124,8 +124,8 @@ export default class InputQuery extends Component {
const { name, type } = input;
const label = `${name ? `${name}: ` : ''}${type}`;
const onChange = (event) => {
const value = event.target.value;
const onChange = (event, input) => {
const value = event && event.target.value || input;
const { values } = this.state;
this.setState({
@ -136,6 +136,19 @@ export default class InputQuery extends Component {
});
};
if (type === 'address') {
return (
<div key={ name }>
<InputAddressSelect
hint={ type }
label={ label }
required
onChange={ onChange }
/>
</div>
);
}
return (
<div key={ name }>
<Input

View File

@ -39,6 +39,7 @@
.txhash {
text-overflow: ellipsis;
width: 20%;
}
.key {
@ -82,6 +83,7 @@
.eventAddress {
display: inline-block;
position: relative;
white-space: nowrap;
}
.eventIdentityicon {

View File

@ -312,7 +312,7 @@ class Contract extends Component {
const contract = api.newContract(account.meta.abi, params.address);
contract
.subscribe(null, { limit: 50, fromBlock: 0, toBlock: 'pending' }, this._receiveEvents)
.subscribe(null, { limit: 25, fromBlock: 0, toBlock: 'pending' }, this._receiveEvents)
.then((subscriptionId) => {
this.setState({ subscriptionId });
});

View File

@ -42,7 +42,7 @@ class Contracts extends Component {
state = {
addContract: false,
deployContract: false,
sortOrder: '',
sortOrder: 'timestamp',
searchValues: [],
searchTokens: []
}
@ -65,6 +65,7 @@ class Contracts extends Component {
balances={ balances }
empty={ !hasContracts }
order={ sortOrder }
orderFallback='name'
handleAddSearchToken={ this.onAddSearchToken } />
</Page>
</div>
@ -80,6 +81,10 @@ class Contracts extends Component {
<ActionbarSort
key='sortAccounts'
order={ this.state.sortOrder }
metas={ [
{ key: 'timestamp', label: 'date' }
] }
showDefault={ false }
onChange={ onChange } />
);
}

View File

@ -36,7 +36,7 @@ use regex::Regex;
use util::RotatingLogger;
use util::log::Colour;
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone)]
pub struct Config {
pub mode: Option<String>,
pub color: bool,

View File

@ -1,10 +1,17 @@
!include WinMessages.nsh
!define WND_CLASS "Parity"
!define WND_TITLE "Parity"
!define WAIT_MS 5000
!define SYNC_TERM 0x00100001
!define APPNAME "Parity"
!define COMPANYNAME "Ethcore"
!define DESCRIPTION "Fast, light, robust Ethereum implementation"
!define VERSIONMAJOR 1
!define VERSIONMINOR 4
!define VERSIONBUILD 0
!define ARGS "--warp --mode=passive"
!addplugindir .\
@ -13,6 +20,10 @@
!define ABOUTURL "https://github.com/ethcore/parity" # "Publisher" link
!define INSTALLSIZE 26120
!define termMsg "Installer cannot stop running ${WND_TITLE}.$\nDo you want to terminate process?"
!define stopMsg "Stopping ${WND_TITLE} Application"
RequestExecutionLevel admin ;Require admin rights on NT6+ (When UAC is turned on)
InstallDir "$PROGRAMFILES64\${COMPANYNAME}\${APPNAME}"
@ -26,7 +37,7 @@ outFile "installer.exe"
page license
page directory
Page instfiles
page instfiles
!macro VerifyUserIsAdmin
UserInfo::GetAccountType
@ -38,6 +49,31 @@ ${If} $0 != "admin" ;Require admin rights on NT4+
${EndIf}
!macroend
!macro TerminateApp
Push $0 ; window handle
Push $1
Push $2 ; process handle
DetailPrint "$(stopMsg)"
FindWindow $0 '${WND_CLASS}' ''
IntCmp $0 0 done
System::Call 'user32.dll::GetWindowThreadProcessId(i r0, *i .r1) i .r2'
System::Call 'kernel32.dll::OpenProcess(i ${SYNC_TERM}, i 0, i r1) i .r2'
SendMessage $0 ${WM_CLOSE} 0 0 /TIMEOUT=${TO_MS}
System::Call 'kernel32.dll::WaitForSingleObject(i r2, i ${WAIT_MS}) i .r1'
IntCmp $1 0 close
MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION "$(termMsg)" /SD IDYES IDYES terminate IDNO close
System::Call 'kernel32.dll::CloseHandle(i r2) i .r1'
Quit
terminate:
System::Call 'kernel32.dll::TerminateProcess(i r2, i 0) i .r1'
close:
System::Call 'kernel32.dll::CloseHandle(i r2) i .r1'
done:
Pop $2
Pop $1
Pop $0
!macroend
function .onInit
setShellVarContext all
!insertmacro VerifyUserIsAdmin
@ -48,10 +84,13 @@ section "install"
setOutPath $INSTDIR
# Files added here should be removed by the uninstaller (see section "uninstall")
file /oname=parity.exe ..\target\release\parity.exe
file /oname=ptray.exe ..\windows\ptray\Release\ptray.exe
file "logo.ico"
file vc_redist.x64.exe
ExecWait '"$INSTDIR\vc_redist.x64.exe" /passive /norestart'
delete $INSTDIR\vc_redist.x64.exe
# Add any other files for the install directory (license files, app data, etc) here
# Uninstaller - See function un.onInit and section "uninstall" for configuration
@ -79,11 +118,11 @@ section "install"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "InstallLocation" "$\"$INSTDIR$\""
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayIcon" "$\"$INSTDIR\logo.ico$\""
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "Publisher" "$\"${COMPANYNAME}$\""
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "Publisher" "${COMPANYNAME}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "HelpLink" "$\"${HELPURL}$\""
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "URLUpdateInfo" "$\"${UPDATEURL}$\""
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "URLInfoAbout" "$\"${ABOUTURL}$\""
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayVersion" "$\"${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}$\""
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayVersion" "${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}"
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "VersionMajor" ${VERSIONMAJOR}
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "VersionMinor" ${VERSIONMINOR}
# There is no option for modifying or repairing the install
@ -91,6 +130,9 @@ section "install"
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "NoRepair" 1
# Set the INSTALLSIZE constant (!defined at the top of this script) so Add/Remove Programs can accurately report the size
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "EstimatedSize" ${INSTALLSIZE}
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Run" ${APPNAME} "$INSTDIR\ptray.exe ${ARGS}"
ExecShell "" "$INSTDIR\ptray.exe" "${ARGS}"
sectionEnd
# Uninstaller
@ -107,7 +149,7 @@ function un.onInit
functionEnd
section "uninstall"
!insertmacro TerminateApp
# Remove Start Menu launcher
delete "$SMPROGRAMS\${COMPANYNAME}\${APPNAME}.lnk"
# Try to remove the Start Menu folder - this will only happen if it is empty
@ -115,6 +157,7 @@ section "uninstall"
# Remove files
delete $INSTDIR\parity.exe
delete $INSTDIR\ptray.exe
delete $INSTDIR\logo.ico
# Always delete uninstaller as the last action
@ -131,5 +174,6 @@ section "uninstall"
# Remove uninstaller information from the registry
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}"
DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "${APPNAME}"
sectionEnd

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

@ -21,7 +21,6 @@ use std::time::{Instant, Duration};
use std::thread::sleep;
use std::sync::Arc;
use rustc_serialize::hex::FromHex;
use ethcore_logger::{setup_log, Config as LogConfig};
use io::{PanicHandler, ForwardPanic};
use util::{ToPretty, Uint};
use rlp::PayloadInfo;
@ -71,7 +70,6 @@ pub enum BlockchainCmd {
#[derive(Debug, PartialEq)]
pub struct ImportBlockchain {
pub spec: SpecType,
pub logger_config: LogConfig,
pub cache_config: CacheConfig,
pub dirs: Directories,
pub file_path: Option<String>,
@ -85,12 +83,12 @@ pub struct ImportBlockchain {
pub fat_db: Switch,
pub vm_type: VMType,
pub check_seal: bool,
pub with_color: bool,
}
#[derive(Debug, PartialEq)]
pub struct ExportBlockchain {
pub spec: SpecType,
pub logger_config: LogConfig,
pub cache_config: CacheConfig,
pub dirs: Directories,
pub file_path: Option<String>,
@ -120,9 +118,6 @@ fn execute_import(cmd: ImportBlockchain) -> Result<String, String> {
// Setup panic handler
let panic_handler = PanicHandler::new_in_arc();
// Setup logging
let _logger = setup_log(&cmd.logger_config);
// create dirs used by parity
try!(cmd.dirs.create_dirs());
@ -196,7 +191,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result<String, String> {
}
};
let informant = Informant::new(client.clone(), None, None, None, cmd.logger_config.color);
let informant = Informant::new(client.clone(), None, None, None, cmd.with_color);
try!(service.register_io_handler(Arc::new(ImportIoHandler {
info: Arc::new(informant),
@ -269,9 +264,6 @@ fn execute_export(cmd: ExportBlockchain) -> Result<String, String> {
// Setup panic handler
let panic_handler = PanicHandler::new_in_arc();
// Setup logging
let _logger = setup_log(&cmd.logger_config);
// create dirs used by parity
try!(cmd.dirs.create_dirs());

View File

@ -35,7 +35,7 @@ use params::{ResealPolicy, AccountsConfig, GasPricerConfig, MinerExtras};
use ethcore_logger::Config as LogConfig;
use dir::Directories;
use dapps::Configuration as DappsConfiguration;
use signer::Configuration as SignerConfiguration;
use signer::{Configuration as SignerConfiguration, SignerCommand};
use run::RunCmd;
use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, DataFormat};
use presale::ImportWallet;
@ -49,11 +49,16 @@ pub enum Cmd {
Account(AccountCmd),
ImportPresaleWallet(ImportWallet),
Blockchain(BlockchainCmd),
SignerToken(String),
SignerToken(SignerCommand),
Snapshot(SnapshotCommand),
Hash(Option<String>),
}
pub struct Execute {
pub logger: LogConfig,
pub cmd: Cmd,
}
#[derive(Debug, PartialEq)]
pub struct Configuration {
pub args: Args,
@ -70,7 +75,7 @@ impl Configuration {
Ok(config)
}
pub fn into_command(self) -> Result<Cmd, String> {
pub fn into_command(self) -> Result<Execute, String> {
let dirs = self.directories();
let pruning = try!(self.args.flag_pruning.parse());
let pruning_history = self.args.flag_pruning_history;
@ -99,7 +104,9 @@ impl Configuration {
let cmd = if self.args.flag_version {
Cmd::Version
} else if self.args.cmd_signer && self.args.cmd_new_token {
Cmd::SignerToken(dirs.signer)
Cmd::SignerToken(SignerCommand {
path: dirs.signer
})
} else if self.args.cmd_tools && self.args.cmd_hash {
Cmd::Hash(self.args.arg_file)
} else if self.args.cmd_account {
@ -141,7 +148,6 @@ impl Configuration {
} else if self.args.cmd_import {
let import_cmd = ImportBlockchain {
spec: spec,
logger_config: logger_config,
cache_config: cache_config,
dirs: dirs,
file_path: self.args.arg_file.clone(),
@ -155,12 +161,12 @@ impl Configuration {
fat_db: fat_db,
vm_type: vm_type,
check_seal: !self.args.flag_no_seal_check,
with_color: logger_config.color,
};
Cmd::Blockchain(BlockchainCmd::Import(import_cmd))
} else if self.args.cmd_export {
let export_cmd = ExportBlockchain {
spec: spec,
logger_config: logger_config,
cache_config: cache_config,
dirs: dirs,
file_path: self.args.arg_file.clone(),
@ -184,7 +190,6 @@ impl Configuration {
spec: spec,
pruning: pruning,
pruning_history: pruning_history,
logger_config: logger_config,
mode: mode,
tracing: tracing,
fat_db: fat_db,
@ -202,7 +207,6 @@ impl Configuration {
spec: spec,
pruning: pruning,
pruning_history: pruning_history,
logger_config: logger_config,
mode: mode,
tracing: tracing,
fat_db: fat_db,
@ -227,7 +231,7 @@ impl Configuration {
pruning: pruning,
pruning_history: pruning_history,
daemon: daemon,
logger_config: logger_config,
logger_config: logger_config.clone(),
miner_options: miner_options,
http_conf: http_conf,
ipc_conf: ipc_conf,
@ -258,7 +262,10 @@ impl Configuration {
Cmd::Run(run_cmd)
};
Ok(cmd)
Ok(Execute {
logger: logger_config,
cmd: cmd,
})
}
fn enable_network(&self, mode: &Mode) -> bool {
@ -684,7 +691,7 @@ mod tests {
use ethcore::miner::{MinerOptions, PrioritizationStrategy};
use helpers::{replace_home, default_network_config};
use run::RunCmd;
use signer::Configuration as SignerConfiguration;
use signer::{Configuration as SignerConfiguration, SignerCommand};
use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, DataFormat};
use presale::ImportWallet;
use account::{AccountCmd, NewAccount, ImportAccounts};
@ -705,14 +712,14 @@ mod tests {
fn test_command_version() {
let args = vec!["parity", "--version"];
let conf = parse(&args);
assert_eq!(conf.into_command().unwrap(), Cmd::Version);
assert_eq!(conf.into_command().unwrap().cmd, Cmd::Version);
}
#[test]
fn test_command_account_new() {
let args = vec!["parity", "account", "new"];
let conf = parse(&args);
assert_eq!(conf.into_command().unwrap(), Cmd::Account(AccountCmd::New(NewAccount {
assert_eq!(conf.into_command().unwrap().cmd, Cmd::Account(AccountCmd::New(NewAccount {
iterations: 10240,
path: replace_home("$HOME/.parity/keys"),
password_file: None,
@ -723,16 +730,16 @@ mod tests {
fn test_command_account_list() {
let args = vec!["parity", "account", "list"];
let conf = parse(&args);
assert_eq!(conf.into_command().unwrap(), Cmd::Account(
AccountCmd::List(replace_home("$HOME/.parity/keys")))
);
assert_eq!(conf.into_command().unwrap().cmd, Cmd::Account(
AccountCmd::List(replace_home("$HOME/.parity/keys")),
));
}
#[test]
fn test_command_account_import() {
let args = vec!["parity", "account", "import", "my_dir", "another_dir"];
let conf = parse(&args);
assert_eq!(conf.into_command().unwrap(), Cmd::Account(AccountCmd::Import(ImportAccounts {
assert_eq!(conf.into_command().unwrap().cmd, Cmd::Account(AccountCmd::Import(ImportAccounts {
from: vec!["my_dir".into(), "another_dir".into()],
to: replace_home("$HOME/.parity/keys"),
})));
@ -742,7 +749,7 @@ mod tests {
fn test_command_wallet_import() {
let args = vec!["parity", "wallet", "import", "my_wallet.json", "--password", "pwd"];
let conf = parse(&args);
assert_eq!(conf.into_command().unwrap(), Cmd::ImportPresaleWallet(ImportWallet {
assert_eq!(conf.into_command().unwrap().cmd, Cmd::ImportPresaleWallet(ImportWallet {
iterations: 10240,
path: replace_home("$HOME/.parity/keys"),
wallet_path: "my_wallet.json".into(),
@ -754,9 +761,8 @@ mod tests {
fn test_command_blockchain_import() {
let args = vec!["parity", "import", "blockchain.json"];
let conf = parse(&args);
assert_eq!(conf.into_command().unwrap(), Cmd::Blockchain(BlockchainCmd::Import(ImportBlockchain {
assert_eq!(conf.into_command().unwrap().cmd, Cmd::Blockchain(BlockchainCmd::Import(ImportBlockchain {
spec: Default::default(),
logger_config: Default::default(),
cache_config: Default::default(),
dirs: Default::default(),
file_path: Some("blockchain.json".into()),
@ -770,6 +776,7 @@ mod tests {
fat_db: Default::default(),
vm_type: VMType::Interpreter,
check_seal: true,
with_color: !cfg!(windows),
})));
}
@ -777,9 +784,8 @@ mod tests {
fn test_command_blockchain_export() {
let args = vec!["parity", "export", "blockchain.json"];
let conf = parse(&args);
assert_eq!(conf.into_command().unwrap(), Cmd::Blockchain(BlockchainCmd::Export(ExportBlockchain {
assert_eq!(conf.into_command().unwrap().cmd, Cmd::Blockchain(BlockchainCmd::Export(ExportBlockchain {
spec: Default::default(),
logger_config: Default::default(),
cache_config: Default::default(),
dirs: Default::default(),
file_path: Some("blockchain.json".into()),
@ -801,9 +807,8 @@ mod tests {
fn test_command_blockchain_export_with_custom_format() {
let args = vec!["parity", "export", "--format", "hex", "blockchain.json"];
let conf = parse(&args);
assert_eq!(conf.into_command().unwrap(), Cmd::Blockchain(BlockchainCmd::Export(ExportBlockchain {
assert_eq!(conf.into_command().unwrap().cmd, Cmd::Blockchain(BlockchainCmd::Export(ExportBlockchain {
spec: Default::default(),
logger_config: Default::default(),
cache_config: Default::default(),
dirs: Default::default(),
file_path: Some("blockchain.json".into()),
@ -826,14 +831,16 @@ mod tests {
let args = vec!["parity", "signer", "new-token"];
let conf = parse(&args);
let expected = replace_home("$HOME/.parity/signer");
assert_eq!(conf.into_command().unwrap(), Cmd::SignerToken(expected));
assert_eq!(conf.into_command().unwrap().cmd, Cmd::SignerToken(SignerCommand {
path: expected,
}));
}
#[test]
fn test_run_cmd() {
let args = vec!["parity"];
let conf = parse(&args);
assert_eq!(conf.into_command().unwrap(), Cmd::Run(RunCmd {
assert_eq!(conf.into_command().unwrap().cmd, Cmd::Run(RunCmd {
cache_config: Default::default(),
dirs: Default::default(),
spec: Default::default(),

View File

@ -114,12 +114,13 @@ mod user_defaults;
mod stratum;
use std::{process, env};
use std::io::BufReader;
use std::io::{self as stdio, BufReader, Write};
use std::fs::File;
use util::sha3::sha3;
use cli::Args;
use configuration::{Cmd, Configuration};
use configuration::{Cmd, Execute, Configuration};
use deprecated::find_deprecated;
use ethcore_logger::setup_log;
fn print_hash_of(maybe_file: Option<String>) -> Result<String, String> {
if let Some(file) = maybe_file {
@ -131,10 +132,12 @@ fn print_hash_of(maybe_file: Option<String>) -> Result<String, String> {
}
}
fn execute(command: Cmd) -> Result<String, String> {
match command {
fn execute(command: Execute) -> Result<String, String> {
let logger = setup_log(&command.logger).expect("Logger is initialized only once; qed");
match command.cmd {
Cmd::Run(run_cmd) => {
try!(run::execute(run_cmd));
try!(run::execute(run_cmd, logger));
Ok("".into())
},
Cmd::Version => Ok(Args::print_version()),
@ -142,7 +145,7 @@ fn execute(command: Cmd) -> Result<String, String> {
Cmd::Account(account_cmd) => account::execute(account_cmd),
Cmd::ImportPresaleWallet(presale_cmd) => presale::execute(presale_cmd),
Cmd::Blockchain(blockchain_cmd) => blockchain::execute(blockchain_cmd),
Cmd::SignerToken(path) => signer::new_token(path),
Cmd::SignerToken(signer_cmd) => signer::execute(signer_cmd),
Cmd::Snapshot(snapshot_cmd) => snapshot::execute(snapshot_cmd),
}
}
@ -198,7 +201,7 @@ fn sync_main() -> bool {
fn main() {
// Always print backtrace on panic.
::std::env::set_var("RUST_BACKTRACE", "1");
if sync_main() {
return;
}
@ -210,7 +213,7 @@ fn main() {
info!("{}", result);
},
Err(err) => {
info!("{}", err);
writeln!(&mut stdio::stderr(), "{}", err).expect("StdErr available; qed");
process::exit(1);
}
}

View File

@ -15,13 +15,14 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::sync::{Arc, Mutex, Condvar};
use std::net::{TcpListener};
use ctrlc::CtrlC;
use fdlimit::raise_fd_limit;
use ethcore_logger::{Config as LogConfig, setup_log};
use ethcore_rpc::{NetworkSettings, is_major_importing};
use ethsync::NetworkConfiguration;
use util::{Colour, version, U256};
use util::{Colour, version, U256, RotatingLogger};
use io::{MayPanic, ForwardPanic, PanicHandler};
use ethcore_logger::{Config as LogConfig};
use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, ChainNotify, BlockChainClient};
use ethcore::service::ClientService;
use ethcore::account_provider::AccountProvider;
@ -93,13 +94,19 @@ pub struct RunCmd {
pub check_seal: bool,
}
pub fn execute(cmd: RunCmd) -> Result<(), String> {
pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<(), String> {
if cmd.ui && cmd.dapps_conf.enabled {
// Check if Parity is already running
let addr = format!("{}:{}", cmd.dapps_conf.interface, cmd.dapps_conf.port);
if !TcpListener::bind(&addr as &str).is_ok() {
url::open(&format!("http://{}:{}/", cmd.dapps_conf.interface, cmd.dapps_conf.port));
return Ok(());
}
}
// set up panic handler
let panic_handler = PanicHandler::new_in_arc();
// set up logger
let logger = try!(setup_log(&cmd.logger_config));
// increase max number of open files
raise_fd_limit();

View File

@ -68,8 +68,13 @@ fn codes_path(path: String) -> PathBuf {
p
}
pub fn new_token(path: String) -> Result<String, String> {
generate_new_token(path)
#[derive(Debug, PartialEq)]
pub struct SignerCommand {
pub path: String,
}
pub fn execute(cmd: SignerCommand) -> Result<String, String> {
generate_new_token(cmd.path)
.map(|code| format!("This key code will authorise your System Signer UI: {}", Colour::White.bold().paint(code)))
.map_err(|err| format!("Error generating token: {:?}", err))
}

View File

@ -20,7 +20,6 @@ use std::time::Duration;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use ethcore_logger::{setup_log, Config as LogConfig};
use ethcore::snapshot::{Progress, RestorationStatus, SnapshotService as SS};
use ethcore::snapshot::io::{SnapshotReader, PackedReader, PackedWriter};
use ethcore::snapshot::service::Service as SnapshotService;
@ -55,7 +54,6 @@ pub struct SnapshotCommand {
pub spec: SpecType,
pub pruning: Pruning,
pub pruning_history: u64,
pub logger_config: LogConfig,
pub mode: Mode,
pub tracing: Switch,
pub fat_db: Switch,
@ -141,9 +139,6 @@ impl SnapshotCommand {
// load user defaults
let user_defaults = try!(UserDefaults::load(&user_defaults_path));
// Setup logging
let _logger = setup_log(&self.logger_config);
fdlimit::raise_fd_limit();
// select pruning algorithm

View File

@ -41,6 +41,7 @@ mod codes {
pub const ACCOUNT_ERROR: i64 = -32023;
pub const SIGNER_DISABLED: i64 = -32030;
pub const DAPPS_DISABLED: i64 = -32031;
pub const NETWORK_DISABLED: i64 = -32035;
pub const REQUEST_REJECTED: i64 = -32040;
pub const REQUEST_REJECTED_LIMIT: i64 = -32041;
pub const REQUEST_NOT_FOUND: i64 = -32042;
@ -185,6 +186,14 @@ pub fn dapps_disabled() -> Error {
}
}
pub fn network_disabled() -> Error {
Error {
code: ErrorCode::ServerError(codes::NETWORK_DISABLED),
message: "Network is disabled or not yet up.".into(),
data: None
}
}
pub fn encryption_error<T: fmt::Debug>(error: T) -> Error {
Error {
code: ErrorCode::ServerError(codes::ENCRYPTION_ERROR),

View File

@ -353,4 +353,8 @@ impl<C, M, S: ?Sized, F> Ethcore for EthcoreClient<C, M, S, F> where
Mode::Active => "active",
}.into())
}
fn enode(&self) -> Result<String, Error> {
take_weak!(self.sync).enode().ok_or_else(errors::network_disabled)
}
}

View File

@ -93,5 +93,9 @@ impl SyncProvider for TestSyncProvider {
}
]
}
fn enode(&self) -> Option<String> {
None
}
}

View File

@ -133,5 +133,9 @@ build_rpc_trait! {
/// Get the mode. Results one of: "active", "passive", "dark", "off".
#[rpc(name = "ethcore_mode")]
fn mode(&self) -> Result<String, Error>;
/// Get the enode of this node.
#[rpc(name = "ethcore_enode")]
fn enode(&self) -> Result<String, Error>;
}
}

View File

@ -73,6 +73,9 @@ pub trait SyncProvider: Send + Sync {
/// Get peers information
fn peers(&self) -> Vec<PeerInfo>;
/// Get the enode if available.
fn enode(&self) -> Option<String>;
}
/// Peer connection information
@ -143,6 +146,10 @@ impl SyncProvider for EthSync {
self.handler.sync.write().peers(&sync_io)
}).unwrap_or(Vec::new())
}
fn enode(&self) -> Option<String> {
self.network.external_url()
}
}
struct SyncProtocolHandler {

View File

@ -32,7 +32,8 @@ use node_table::NodeId;
use stats::NetworkStats;
use time;
const PING_TIMEOUT_SEC: u64 = 65;
// Timeout must be less than (interval - 1).
const PING_TIMEOUT_SEC: u64 = 15;
const PING_INTERVAL_SEC: u64 = 30;
/// Peer session over encrypted connection.

View File

@ -30,7 +30,7 @@ pub struct Histogram {
impl Histogram {
/// Histogram if a sorted corpus is at least fills the buckets.
pub fn new(corpus: &[U256], bucket_number: usize) -> Option<Histogram> {
if corpus.len() < bucket_number { return None; }
if corpus.len() <= bucket_number { return None; }
let corpus_end = corpus.last().expect("there are at least bucket_number elements; qed").clone();
// If there are extremely few transactions, go from zero.
let corpus_start = corpus.first().expect("there are at least bucket_number elements; qed").clone();
@ -67,4 +67,9 @@ mod tests {
assert!(Histogram::new(&vec_into![1, 2], 5).is_none());
}
#[test]
fn should_not_panic_when_asking_for_bucket_too_big() {
assert!(Histogram::new(&vec_into![1, 2], 2).is_none());
}
}

274
windows/ptray/ptray.cpp Normal file
View File

@ -0,0 +1,274 @@
// Copyright 2015, 2016 Ethcore (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/>.
#define WIN32_LEAN_AND_MEAN
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <Windows.h>
#include <Shellapi.h>
#include <Shlwapi.h>
#include <tlhelp32.h>
#include <SDKDDKVer.h>
#include "resource.h"
#pragma comment(lib, "shlwapi.lib")
#define MAX_LOADSTRING 100
#define IDM_EXIT 100
#define IDM_OPEN 101
#define WM_USER_SHELLICON WM_USER + 1
HANDLE parityHandle = INVALID_HANDLE_VALUE;
DWORD parityProcId = 0;
NOTIFYICONDATA nidApp;
WCHAR szTitle[MAX_LOADSTRING];
WCHAR szWindowClass[MAX_LOADSTRING];
LPCWSTR cParityExe = _T("parity.exe");
ATOM MyRegisterClass(HINSTANCE hInstance);
bool InitInstance(HINSTANCE, int, LPWSTR cmdLine);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void KillParity();
void OpenUI();
bool ParityIsRunning();
bool GetParityExePath(TCHAR* dest, size_t destSize)
{
if (!dest || MAX_PATH > destSize)
return false;
GetModuleFileName(NULL, dest, destSize);
if (!PathRemoveFileSpec(dest))
return false;
return PathAppend(dest, _T("parity.exe")) == TRUE;
}
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
CreateMutex(0, FALSE, _T("Local\\ParityTray"));
if (GetLastError() == ERROR_ALREADY_EXISTS)
return -1;
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_PTRAY, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
if (!InitInstance(hInstance, nCmdShow, lpCmdLine))
return FALSE;
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_PTRAY));
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PTRAY));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_PTRAY);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
bool InitInstance(HINSTANCE hInstance, int nCmdShow, LPWSTR cmdLine)
{
// Check if already running
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(snapshot, &entry) == TRUE)
{
while (Process32Next(snapshot, &entry) == TRUE)
{
if (lstrcmp(entry.szExeFile, cParityExe) == 0)
{
parityHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
parityProcId = entry.th32ProcessID;
break;
}
}
}
CloseHandle(snapshot);
if (parityHandle == INVALID_HANDLE_VALUE)
{
// Launch parity
TCHAR path[MAX_PATH] = { 0 };
if (!GetParityExePath(path, MAX_PATH))
return false;
PROCESS_INFORMATION procInfo = { 0 };
STARTUPINFO startupInfo = { sizeof(STARTUPINFO) };
LPWSTR cmd = new WCHAR[lstrlen(cmdLine) + lstrlen(path) + 2];
lstrcpy(cmd, path);
lstrcat(cmd, _T(" "));
lstrcat(cmd, cmdLine);
if (!CreateProcess(nullptr, cmd, nullptr, nullptr, false, CREATE_NO_WINDOW, nullptr, nullptr, &startupInfo, &procInfo))
return false;
delete[] cmd;
parityHandle = procInfo.hProcess;
parityProcId = procInfo.dwProcessId;
}
HWND hWnd = CreateWindowW(szWindowClass, szTitle, 0,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
return false;
HICON hMainIcon = LoadIcon(hInstance, (LPCTSTR)MAKEINTRESOURCE(IDI_PTRAY));
nidApp.cbSize = sizeof(NOTIFYICONDATA); // sizeof the struct in bytes
nidApp.hWnd = (HWND)hWnd; //handle of the window which will process this app. messages
nidApp.uID = IDI_PTRAY; //ID of the icon that willl appear in the system tray
nidApp.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; //ORing of all the flags
nidApp.hIcon = hMainIcon; // handle of the Icon to be displayed, obtained from LoadIcon
nidApp.uCallbackMessage = WM_USER_SHELLICON;
LoadString(hInstance, IDS_CONTROL_PARITY, nidApp.szTip, MAX_LOADSTRING);
Shell_NotifyIcon(NIM_ADD, &nidApp);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_USER_SHELLICON:
// systray msg callback
POINT lpClickPoint;
switch (LOWORD(lParam))
{
case WM_LBUTTONDOWN:
OpenUI();
break;
case WM_RBUTTONDOWN:
UINT uFlag = MF_BYPOSITION | MF_STRING;
GetCursorPos(&lpClickPoint);
HMENU hPopMenu = CreatePopupMenu();
InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING, IDM_EXIT, _T("Open"));
InsertMenu(hPopMenu, 0xFFFFFFFF, MF_SEPARATOR | MF_BYPOSITION, 0, nullptr);
InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING, IDM_EXIT, _T("Exit"));
SetForegroundWindow(hWnd);
TrackPopupMenu(hPopMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_BOTTOMALIGN, lpClickPoint.x, lpClickPoint.y, 0, hWnd, NULL);
return TRUE;
}
break;
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case IDM_OPEN:
OpenUI();
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_DESTROY:
Shell_NotifyIcon(NIM_DELETE, &nidApp);
KillParity();
PostQuitMessage(0);
break;
case WM_TIMER:
if (!ParityIsRunning())
DestroyWindow(hWnd);
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
void KillParity()
{
DWORD procId = parityProcId;
//This does not require the console window to be visible.
if (AttachConsole(procId))
{
// Disable Ctrl-C handling for our program
SetConsoleCtrlHandler(nullptr, true);
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
FreeConsole();
//Re-enable Ctrl-C handling or any subsequently started
//programs will inherit the disabled state.
SetConsoleCtrlHandler(nullptr, false);
}
WaitForSingleObject(parityHandle, INFINITE);
}
bool ParityIsRunning()
{
return WaitForSingleObject(parityHandle, 0) == WAIT_TIMEOUT;
}
void OpenUI()
{
// Launch parity
TCHAR path[MAX_PATH] = { 0 };
if (!GetParityExePath(path, MAX_PATH))
return;
PROCESS_INFORMATION procInfo = { 0 };
STARTUPINFO startupInfo = { sizeof(STARTUPINFO) };
LPWSTR cmd = _T("parity.exe ui");
CreateProcess(path, cmd, nullptr, nullptr, false, CREATE_NO_WINDOW, nullptr, nullptr, &startupInfo, &procInfo);
}

BIN
windows/ptray/ptray.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
windows/ptray/ptray.rc Normal file

Binary file not shown.

155
windows/ptray/ptray.vcxproj Normal file
View File

@ -0,0 +1,155 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{37C89E90-8C9E-4FFC-AAE7-B3695D5EB6F4}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>ptray</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="Resource.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="ptray.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="ptray.rc" />
</ItemGroup>
<ItemGroup>
<Image Include="ptray.ico" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

BIN
windows/ptray/resource.h Normal file

Binary file not shown.

View File

@ -0,0 +1,8 @@
#pragma once
// Including SDKDDKVer.h defines the highest available Windows platform.
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
#include <SDKDDKVer.h>