Compare commits

..

14 Commits

Author SHA1 Message Date
Afri Schoedon
1de095f3bd Backport Master CI PRs to Beta (#7890)
* Resolve conflicts

* Resolve conflicts

* Update gitlab-build.sh (#7855)

fix build ```version``` after https://github.com/paritytech/parity/pull/7723

* Resolve conflicts

* Update gitlab-test.sh (#7883)

* Update gitlab-test.sh

https://github.com/paritytech/parity/issues/7871

* Update aura-test.sh

* Backport master ci prs

* Bump beta to 1.9.3

* Make track beta

* Downgrade rustc_version
2018-02-14 16:59:16 +01:00
Tomasz Drwięga
b60511e3d2 Backport Core PRs to beta (#7891)
* update back-references more aggressively after answering from cache (#7578)

* Add new EF ropstens nodes. (#7824)

* Add new EF ropstens nodes.

* Fix tests

* Add a timeout for light client sync requests (#7848)

* Add a timeout for light client sync requests

* Adjusting timeout to number of headers

* Flush keyfiles. Resolves #7632 (#7868)

* Fix wallet import (#7873)

* rpc: generate new account id for imported wallets

* ethstore: handle duplicate wallet filenames

* ethstore: simplify deduplication of wallet file names

* ethstore: do not dedup wallet filenames on update

* ethstore: fix minor grumbles

* [WASM] mem_cmp added to the Wasm runtime (#7539)

* mem_cmp added to the Wasm runtime

* schedule.wasm.mem_copy to schedule.wasm.mem_cmp for mem_cmp

* [Wasm] memcmp fix and test added (#7590)

* [Wasm] memcmp fix and test added

* [Wasm] use reqrep_test! macro for memcmp test

* wasmi interpreter (#7796)

* adjust storage update evm-style (#7812)

* disable internal memory (#7842)
2018-02-14 16:13:38 +01:00
GitLab Build Bot
af70a681d5 [ci skip] js-precompiled 20180212-180349 2018-02-12 18:04:52 +00:00
GitLab Build Bot
7adfb82076 [ci skip] js-precompiled 20180202-122111 2018-02-02 12:22:09 +00:00
GitLab Build Bot
d504ce64e8 [ci skip] js-precompiled 20180202-081050 2018-02-02 08:11:54 +00:00
Afri Schoedon
0feb0bb6e7 Backports beta (#7780)
* Bump beta to 1.9.2

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

* Filter-out nodes.json

* network: sort node table nodes by failure ratio

* network: fix node table tests

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

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

* network: fix node table grumbles

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

* parity: wait for client to drop on shutdown

* parity: fix grumbles in shutdown wait

* parity: increase shutdown timeouts

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

* Update Clap dependency and remove workarounds

* WIP

* Remove line breaks in help messages for now

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

* Grumbles; refactor repeating code; add constant

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

* Wrap --help to 120 characters rather than 100 characters
2018-01-31 21:45:23 +01:00
GitLab Build Bot
582fa8ce45 [ci skip] js-precompiled 20180131-171157 2018-01-31 17:13:01 +00:00
49 changed files with 1852 additions and 1651 deletions

View File

@@ -9,7 +9,7 @@ trim_trailing_whitespace=true
max_line_length=120
insert_final_newline=true
[.travis.yml]
[*.{yml,sh}]
indent_style=space
indent_size=2
tab_width=8

View File

@@ -24,8 +24,8 @@ linux-stable:
- triggers
script:
- rustup default stable
# ARGUMENTS: 1. BUILD_PLATFORM (target for binaries) 2. PLATFORM (target for cargo) 3. ARC (architecture) 4. & 5. CC & CXX flags
- scripts/gitlab-build.sh x86_64-unknown-linux-gnu x86_64-unknown-linux-gnu amd64 gcc g++
# ARGUMENTS: 1. BUILD_PLATFORM (target for binaries) 2. PLATFORM (target for cargo) 3. ARC (architecture) 4. & 5. CC & CXX flags 6. binary identifier
- scripts/gitlab-build.sh x86_64-unknown-linux-gnu x86_64-unknown-linux-gnu amd64 gcc g++ ubuntu
tags:
- rust-stable
artifacts:
@@ -42,7 +42,7 @@ linux-stable-debian:
- triggers
script:
- export LIBSSL="libssl1.1 (>=1.1.0)"
- scripts/gitlab-build.sh x86_64-unknown-debian-gnu x86_64-unknown-linux-gnu amd64 gcc g++
- scripts/gitlab-build.sh x86_64-unknown-debian-gnu x86_64-unknown-linux-gnu amd64 gcc g++ debian
tags:
- rust-debian
artifacts:
@@ -58,7 +58,7 @@ linux-centos:
- stable
- triggers
script:
- scripts/gitlab-build.sh x86_64-unknown-centos-gnu x86_64-unknown-linux-gnu x86_64 gcc g++
- scripts/gitlab-build.sh x86_64-unknown-centos-gnu x86_64-unknown-linux-gnu x86_64 gcc g++ centos
tags:
- rust-centos
artifacts:
@@ -74,7 +74,7 @@ linux-i686:
- stable
- triggers
script:
- scripts/gitlab-build.sh i686-unknown-linux-gnu i686-unknown-linux-gnu i386 gcc g++
- scripts/gitlab-build.sh i686-unknown-linux-gnu i686-unknown-linux-gnu i386 gcc g++ ubuntu
tags:
- rust-i686
artifacts:
@@ -90,7 +90,7 @@ linux-armv7:
- stable
- triggers
script:
- scripts/gitlab-build.sh armv7-unknown-linux-gnueabihf armv7-unknown-linux-gnueabihf armhf arm-linux-gnueabihf-gcc arm-linux-gnueabihf-g++
- scripts/gitlab-build.sh armv7-unknown-linux-gnueabihf armv7-unknown-linux-gnueabihf armhf arm-linux-gnueabihf-gcc arm-linux-gnueabihf-g++ ubuntu
tags:
- rust-arm
artifacts:
@@ -106,7 +106,7 @@ linux-arm:
- stable
- triggers
script:
- scripts/gitlab-build.sh arm-unknown-linux-gnueabihf arm-unknown-linux-gnueabihf armhf arm-linux-gnueabihf-gcc arm-linux-gnueabihf-g++
- scripts/gitlab-build.sh arm-unknown-linux-gnueabihf arm-unknown-linux-gnueabihf armhf arm-linux-gnueabihf-gcc arm-linux-gnueabihf-g++ ubuntu
tags:
- rust-arm
artifacts:
@@ -122,7 +122,7 @@ linux-aarch64:
- stable
- triggers
script:
- scripts/gitlab-build.sh aarch64-unknown-linux-gnu aarch64-unknown-linux-gnu arm64 aarch64-linux-gnu-gcc aarch64-linux-gnu-g++
- scripts/gitlab-build.sh aarch64-unknown-linux-gnu aarch64-unknown-linux-gnu arm64 aarch64-linux-gnu-gcc aarch64-linux-gnu-g++ ubuntu
tags:
- rust-arm
artifacts:
@@ -131,19 +131,19 @@ linux-aarch64:
name: "aarch64-unknown-linux-gnu_parity"
linux-snap:
stage: build
image: parity/snapcraft:gitlab-ci
image: snapcore/snapcraft:stable
only:
- stable
- beta
- tags
- triggers
script:
- scripts/gitlab-build.sh x86_64-unknown-snap-gnu x86_64-unknown-linux-gnu amd64 gcc g++
- scripts/gitlab-build.sh x86_64-unknown-snap-gnu x86_64-unknown-linux-gnu amd64 gcc g++ snap
tags:
- rust-stable
artifacts:
paths:
- scripts/parity_*_amd64.snap
- parity.zip
name: "stable-x86_64-unknown-snap-gnu_parity"
allow_failure: true
darwin:
@@ -154,7 +154,7 @@ darwin:
- stable
- triggers
script:
- scripts/gitlab-build.sh x86_64-apple-darwin x86_64-apple-darwin macos gcc g++
- scripts/gitlab-build.sh x86_64-apple-darwin x86_64-apple-darwin macos gcc g++ macos
tags:
- osx
artifacts:
@@ -172,7 +172,7 @@ windows:
- stable
- triggers
script:
- sh scripts/gitlab-build.sh x86_64-pc-windows-msvc x86_64-pc-windows-msvc installer "" "" ""
- sh scripts/gitlab-build.sh x86_64-pc-windows-msvc x86_64-pc-windows-msvc installer "" "" windows
tags:
- rust-windows
artifacts:
@@ -187,7 +187,7 @@ docker-build:
before_script:
- docker info
script:
- DOCKER_TAG=$CI_BUILD_REF_NAME
- if [ "$CI_BUILD_REF_NAME" == "beta-release" ]; then DOCKER_TAG="latest"; else DOCKER_TAG=$CI_BUILD_REF_NAME; fi
- echo "Tag:" $DOCKER_TAG
- docker login -u $Docker_Hub_User_Parity -p $Docker_Hub_Pass_Parity
- scripts/docker-build.sh $DOCKER_TAG
@@ -244,8 +244,8 @@ js-release:
stage: js-build
only:
- master
- beta
- stable
- beta
- tags
- triggers
image: parity/rust:gitlab-ci
@@ -260,8 +260,6 @@ push-release:
- triggers
image: parity/rust:gitlab-ci
script:
- rustup default stable
- curl --data "secret=$RELEASES_SECRET" http://update.parity.io:1337/push-release/$CI_BUILD_REF_NAME/$CI_BUILD_REF
- curl --data "secret=$RELEASES_SECRET" http://update.parity.io:1338/push-release/$CI_BUILD_REF_NAME/$CI_BUILD_REF
- scripts/gitlab-push-release.sh
tags:
- curl

89
Cargo.lock generated
View File

@@ -25,6 +25,11 @@ name = "ansi_term"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ansi_term"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "app_dirs"
version = "1.1.1"
@@ -163,6 +168,11 @@ name = "bitflags"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bloomable"
version = "0.1.0"
@@ -234,15 +244,14 @@ dependencies = [
[[package]]
name = "clap"
version = "2.26.2"
version = "2.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -663,6 +672,8 @@ dependencies = [
"rlp 0.2.1",
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)",
@@ -1903,11 +1914,11 @@ dependencies = [
[[package]]
name = "parity"
version = "1.9.1"
version = "1.9.3"
dependencies = [
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)",
"daemonize 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"dir 0.1.0",
@@ -1951,7 +1962,7 @@ dependencies = [
"parity-rpc 1.9.0",
"parity-rpc-client 1.4.0",
"parity-updater 1.9.0",
"parity-version 1.9.1",
"parity-version 1.9.3",
"parity-whisper 0.1.0",
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"path 0.1.0",
@@ -1966,6 +1977,8 @@ dependencies = [
"serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1997,7 +2010,7 @@ dependencies = [
"parity-hash-fetch 1.9.0",
"parity-reactor 0.1.0",
"parity-ui 1.9.0",
"parity-version 1.9.1",
"parity-version 1.9.3",
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2145,7 +2158,7 @@ dependencies = [
"order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-reactor 0.1.0",
"parity-updater 1.9.0",
"parity-version 1.9.1",
"parity-version 1.9.3",
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2226,7 +2239,7 @@ dependencies = [
[[package]]
name = "parity-ui-old-precompiled"
version = "1.9.0"
source = "git+https://github.com/js-dist-paritytech/parity-beta-1-9-v1.git#bb21e9f134f1d32b878e90e60e83ef84550f032c"
source = "git+https://github.com/js-dist-paritytech/parity-beta-1-9-v1.git#2997296ebba9a48ec8254f172699fcc215dbf8a0"
dependencies = [
"parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -2234,7 +2247,7 @@ dependencies = [
[[package]]
name = "parity-ui-precompiled"
version = "1.9.0"
source = "git+https://github.com/js-dist-paritytech/parity-beta-1-9-shell.git#630c81d25c268472dbf1ebef60f39852d2805542"
source = "git+https://github.com/js-dist-paritytech/parity-beta-1-9-shell.git#81e795b68518c3d8b57ee09fd3305141958eca99"
dependencies = [
"parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -2253,7 +2266,7 @@ dependencies = [
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-hash-fetch 1.9.0",
"parity-reactor 0.1.0",
"parity-version 1.9.1",
"parity-version 1.9.3",
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"path 0.1.0",
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2262,23 +2275,24 @@ dependencies = [
[[package]]
name = "parity-version"
version = "1.9.1"
version = "1.9.3"
dependencies = [
"ethcore-bytes 0.1.0",
"rlp 0.2.1",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"vergen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parity-wasm"
version = "0.15.3"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -2329,6 +2343,15 @@ dependencies = [
"parking_lot_core 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parking_lot"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot_core 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parking_lot_core"
version = "0.2.6"
@@ -2505,7 +2528,7 @@ dependencies = [
name = "pwasm-run-test"
version = "0.1.0"
dependencies = [
"clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-bigint 0.2.1",
"ethcore-logger 1.9.0",
"ethjson 0.1.0",
@@ -3113,10 +3136,9 @@ dependencies = [
[[package]]
name = "textwrap"
version = "0.8.0"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -3465,24 +3487,35 @@ dependencies = [
"ethcore-bigint 0.2.1",
"ethcore-logger 1.9.0",
"ethcore-util 1.9.0",
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-wasm 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-wasm 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
"vm 0.1.0",
"wasm-utils 0.1.0 (git+https://github.com/paritytech/wasm-utils)",
"wasmi 0.0.0 (git+https://github.com/pepyakin/wasmi)",
]
[[package]]
name = "wasm-utils"
version = "0.1.0"
source = "git+https://github.com/paritytech/wasm-utils#3d59f7ca0661317bc66894a26b2a5a319fa5d229"
source = "git+https://github.com/paritytech/wasm-utils#6fdc1c4ed47a6acb0a4774da505a416dd637bc6d"
dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-wasm 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-wasm 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wasmi"
version = "0.0.0"
source = "git+https://github.com/pepyakin/wasmi#551c99273042deaad869c17798060e2212deacab"
dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-wasm 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -3556,6 +3589,7 @@ dependencies = [
"checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45"
"checksum advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a"
"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
"checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455"
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
"checksum app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7d1c0d48a81bbb13043847f957971f4d87c81542d80ece5e84ba3cba4058fd4"
"checksum arrayvec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1c0250693b17316353df525fb088da32a8c18f84eb65d113dde31f5a76ed17b6"
@@ -3574,6 +3608,7 @@ dependencies = [
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4"
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
"checksum bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f421095d2a76fc24cd3fb3f912b90df06be7689912b1bdb423caefae59c258d"
"checksum bn 0.4.4 (git+https://github.com/paritytech/bn)" = "<none>"
"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d"
@@ -3581,7 +3616,7 @@ dependencies = [
"checksum cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7db2f146208d7e0fbee761b09cd65a7f51ccc38705d4e7262dad4d73b12a76b1"
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
"checksum cid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "34aa7da06f10541fbca6850719cdaa8fa03060a5d2fb33840f149cf8133a00c7"
"checksum clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3451e409013178663435d6f15fdb212f14ee4424a3d74f979d081d0a66b6f1f2"
"checksum clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8f4a2b3bb7ef3c672d7c13d15613211d5a6976b6892c598b0fcb5d40765f19c2"
"checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd"
"checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299"
"checksum cookie 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d53b80dde876f47f03cda35303e368a79b91c70b0d65ecba5fd5280944a08591"
@@ -3698,9 +3733,10 @@ dependencies = [
"checksum parity-tokio-ipc 0.1.5 (git+https://github.com/nikvolf/parity-tokio-ipc)" = "<none>"
"checksum parity-ui-old-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-beta-1-9-v1.git)" = "<none>"
"checksum parity-ui-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-beta-1-9-shell.git)" = "<none>"
"checksum parity-wasm 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8431a184ad88cfbcd71a792aaca319cc7203a94300c26b8dce2d0df0681ea87d"
"checksum parity-wasm 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ba4b1d4236b76694f6ab8d8d00cdbe1e37c6dd1b5c803d26721f27e097d4d9"
"checksum parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0dec124478845b142f68b446cbee953d14d4b41f1bc0425024417720dce693"
"checksum parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e"
"checksum parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3e7f7c9857874e54afeb950eebeae662b1e51a2493666d2ea4c0a5d91dcf0412"
"checksum parking_lot_core 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4f610cb9664da38e417ea3225f23051f589851999535290e077939838ab7a595"
"checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356"
"checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc"
@@ -3785,7 +3821,7 @@ dependencies = [
"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
"checksum textwrap 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8e08afc40ae3459e4838f303e465aa50d823df8d7f83ca88108f6d3afe7edd"
"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14"
"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865"
"checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520"
@@ -3822,6 +3858,7 @@ dependencies = [
"checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum wasm-utils 0.1.0 (git+https://github.com/paritytech/wasm-utils)" = "<none>"
"checksum wasmi 0.0.0 (git+https://github.com/pepyakin/wasmi)" = "<none>"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
"checksum ws 0.7.1 (git+https://github.com/tomusdrw/ws-rs)" = "<none>"

View File

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

View File

@@ -90,7 +90,14 @@ impl Pending {
match self.requests[idx].respond_local(cache) {
Some(response) => {
self.requests.supply_response_unchecked(&response);
// update header and back-references after each from-cache
// response to ensure that the requests are left in a consistent
// state and increase the likelihood of being able to answer
// the next request from cache.
self.update_header_refs(idx, &response);
self.fill_unanswered();
self.responses.push(response);
}
None => break,

View File

@@ -52,8 +52,10 @@
"gasLimit": "0x1000000"
},
"nodes": [
"enode://20c9ad97c081d63397d7b685a412227a40e23c8bdc6688c6f37e97cfbc22d2b4d1db1510d8f61e6a8866ad7f0e17c02b14182d37ea7c3c8b9c2683aeb6b733a1@52.169.14.227:30303",
"enode://6ce05930c72abc632c58e2e4324f7c7ea478cec0ed4fa2528982cf34483094e9cbc9216e7aa349691242576d552a2a56aaeae426c5303ded677ce455ba1acd9d@13.84.180.240:30303"
"enode://6332792c4a00e3e4ee0926ed89e0d27ef985424d97b6a45bf0f23e51f0dcb5e66b875777506458aea7af6f9e4ffb69f43f3778ee73c81ed9d34c51c4b16b0b0f@52.232.243.152:30303",
"enode://94c15d1b9e2fe7ce56e458b9a3b672ef11894ddedd0c6f247e0f1d3487f52b66208fb4aeb8179fce6e3a749ea93ed147c37976d67af557508d199d9594c35f09@192.81.208.223:30303",
"enode://30b7ab30a01c124a6cceca36863ece12c4f5fa68e3ba9b0b51407ccc002eeed3b3102d20a88f1c1d3c3154e2449317b8ef95090e77b312d5cc39354f86d5d606@52.176.7.10:30303",
"enode://865a63255b3bb68023b6bffd5095118fcc13e79dcf014fe4e47e065c350c7cc72af2e53eff895f11ba1bbb6a2b33271c1116ee870f266618eadfc2e78aa7349c@52.176.100.77:30303"
],
"accounts": {
"0000000000000000000000000000000000000000": { "balance": "1" },

View File

@@ -264,9 +264,9 @@ impl AccountProvider {
Ok(Address::from(account.address).into())
}
/// Import a new presale wallet.
pub fn import_wallet(&self, json: &[u8], password: &str) -> Result<Address, Error> {
let account = self.sstore.import_wallet(SecretVaultRef::Root, json, password)?;
/// Import a new wallet.
pub fn import_wallet(&self, json: &[u8], password: &str, gen_id: bool) -> Result<Address, Error> {
let account = self.sstore.import_wallet(SecretVaultRef::Root, json, password, gen_id)?;
if self.blacklisted_accounts.contains(&account.address) {
self.sstore.remove_account(&account, password)?;
return Err(SSError::InvalidAccount.into());

View File

@@ -156,11 +156,7 @@ impl TransactOptions<trace::NoopTracer, trace::NoopVMTracer> {
pub fn executor(machine: &Machine, vm_factory: &Factory, params: &ActionParams) -> Box<vm::Vm> {
if machine.supports_wasm() && params.code.as_ref().map_or(false, |code| code.len() > 4 && &code[0..4] == WASM_MAGIC_NUMBER) {
Box::new(
wasm::WasmInterpreter::new()
// prefer to fail fast
.expect("Failed to create wasm runtime")
)
Box::new(wasm::WasmInterpreter)
} else {
vm_factory.create(params.gas)
}

View File

@@ -127,18 +127,19 @@ pub struct WasmCosts {
pub mul: u32,
/// Memory (load/store) operations multiplier.
pub mem: u32,
/// Memory copy operation, per byte.
pub mem_copy: u32,
/// Memory move operation, per byte.
pub mem_move: u32,
/// Memory set operation, per byte.
pub mem_set: u32,
/// Static region charge, per byte.
pub static_region: u32,
/// General static query of U256 value from env-info
pub static_u256: u32,
/// General static query of Address value from env-info
pub static_address: u32,
/// Memory stipend. Amount of free memory (in 64kb pages) each contract can use for stack.
pub initial_mem: u32,
/// Grow memory cost, per page (64kb)
pub grow_mem: u32,
/// Cost of wasm opcode is calculated as TABLE_ENTRY_COST * `opcodes_mul` / `opcodes_div`
pub opcodes_mul: u32,
/// Cost of wasm opcode is calculated as TABLE_ENTRY_COST * `opcodes_mul` / `opcodes_div`
pub opcodes_div: u32,
}
impl Default for WasmCosts {
@@ -148,12 +149,12 @@ impl Default for WasmCosts {
div: 16,
mul: 4,
mem: 2,
mem_copy: 1,
mem_move: 1,
mem_set: 1,
static_region: 1,
static_u256: 64,
static_address: 40,
initial_mem: 4096,
grow_mem: 8192,
opcodes_mul: 3,
opcodes_div: 8,
}
}
}

View File

@@ -8,7 +8,9 @@ byteorder = "1.0"
ethcore-util = { path = "../../util" }
ethcore-bigint = { path = "../../util/bigint" }
log = "0.3"
parity-wasm = "0.15"
parity-wasm = "0.23"
libc = "0.2"
wasm-utils = { git = "https://github.com/paritytech/wasm-utils" }
vm = { path = "../vm" }
ethcore-logger = { path = "../../logger" }
wasmi = { git = "https://github.com/pepyakin/wasmi" }

View File

@@ -16,7 +16,7 @@ fn load_code<P: AsRef<path::Path>>(p: P) -> io::Result<Vec<u8>> {
}
fn wasm_interpreter() -> WasmInterpreter {
WasmInterpreter::new().expect("wasm interpreter to create without errors")
WasmInterpreter
}
#[derive(Debug)]

View File

@@ -14,178 +14,279 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Wasm env module bindings
//! Env module glue for wasmi interpreter
use parity_wasm::elements::ValueType::*;
use parity_wasm::interpreter::{self, UserFunctionDescriptor};
use parity_wasm::interpreter::UserFunctionDescriptor::*;
use super::runtime::{Runtime, UserTrap};
use std::cell::RefCell;
use wasmi::{
self, Signature, Error, FuncRef, FuncInstance, MemoryDescriptor,
MemoryRef, MemoryInstance,
};
pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
Static(
"_storage_read",
&[I32; 2],
/// Internal ids all functions runtime supports. This is just a glue for wasmi interpreter
/// that lacks high-level api and later will be factored out
pub mod ids {
pub const STORAGE_WRITE_FUNC: usize = 0;
pub const STORAGE_READ_FUNC: usize = 10;
pub const RET_FUNC: usize = 20;
pub const GAS_FUNC: usize = 30;
pub const FETCH_INPUT_FUNC: usize = 40;
pub const INPUT_LENGTH_FUNC: usize = 50;
pub const CCALL_FUNC: usize = 60;
pub const SCALL_FUNC: usize = 70;
pub const DCALL_FUNC: usize = 80;
pub const VALUE_FUNC: usize = 90;
pub const CREATE_FUNC: usize = 100;
pub const SUICIDE_FUNC: usize = 110;
pub const BLOCKHASH_FUNC: usize = 120;
pub const BLOCKNUMBER_FUNC: usize = 130;
pub const COINBASE_FUNC: usize = 140;
pub const DIFFICULTY_FUNC: usize = 150;
pub const GASLIMIT_FUNC: usize = 160;
pub const TIMESTAMP_FUNC: usize = 170;
pub const ADDRESS_FUNC: usize = 180;
pub const SENDER_FUNC: usize = 190;
pub const ORIGIN_FUNC: usize = 200;
pub const ELOG_FUNC: usize = 210;
pub const PANIC_FUNC: usize = 1000;
pub const DEBUG_FUNC: usize = 1010;
}
/// Signatures of all functions runtime supports. The actual dispatch happens at
/// impl runtime::Runtime methods.
pub mod signatures {
use wasmi::{self, ValueType};
use wasmi::ValueType::*;
pub struct StaticSignature(pub &'static [ValueType], pub Option<ValueType>);
pub const STORAGE_READ: StaticSignature = StaticSignature(
&[I32, I32],
None,
),
Static(
"_storage_write",
&[I32; 2],
);
pub const STORAGE_WRITE: StaticSignature = StaticSignature(
&[I32, I32],
None,
),
Static(
"_balance",
&[I32; 2],
);
pub const RET: StaticSignature = StaticSignature(
&[I32, I32],
None,
),
Static(
"_ext_malloc",
);
pub const GAS: StaticSignature = StaticSignature(
&[I32],
None,
);
pub const FETCH_INPUT: StaticSignature = StaticSignature(
&[I32],
None,
);
pub const INPUT_LENGTH: StaticSignature = StaticSignature(
&[],
Some(I32),
),
Static(
"_ext_free",
&[I32],
None,
),
Static(
"gas",
&[I32],
None,
),
Static(
"_debug",
&[I32; 2],
None,
),
Static(
"_suicide",
&[I32],
None,
),
Static(
"_create",
&[I32; 4],
Some(I32),
),
Static(
"_ccall",
);
pub const CCALL: StaticSignature = StaticSignature(
&[I64, I32, I32, I32, I32, I32, I32],
Some(I32),
),
Static(
"_dcall",
);
pub const DCALL: StaticSignature = StaticSignature(
&[I64, I32, I32, I32, I32, I32],
Some(I32),
),
Static(
"_scall",
);
pub const SCALL: StaticSignature = StaticSignature(
&[I64, I32, I32, I32, I32, I32],
Some(I32),
),
Static(
"abort",
);
pub const PANIC: StaticSignature = StaticSignature(
&[I32, I32],
None,
);
pub const DEBUG: StaticSignature = StaticSignature(
&[I32, I32],
None,
);
pub const VALUE: StaticSignature = StaticSignature(
&[I32],
None,
),
Static(
"_emscripten_memcpy_big",
&[I32; 3],
);
pub const CREATE: StaticSignature = StaticSignature(
&[I32, I32, I32, I32],
Some(I32),
),
Static(
"_ext_memcpy",
&[I32; 3],
Some(I32),
),
Static(
"_ext_memset",
&[I32; 3],
Some(I32),
),
Static(
"_ext_memmove",
&[I32; 3],
Some(I32),
),
Static(
"_panic",
&[I32; 2],
);
pub const SUICIDE: StaticSignature = StaticSignature(
&[I32],
None,
),
Static(
"_blockhash",
);
pub const BLOCKHASH: StaticSignature = StaticSignature(
&[I64, I32],
None,
),
Static(
"_coinbase",
&[I32],
None,
),
Static(
"_sender",
&[I32],
None,
),
Static(
"_origin",
&[I32],
None,
),
Static(
"_address",
&[I32],
None,
),
Static(
"_value",
&[I32],
None,
),
Static(
"_timestamp",
);
pub const BLOCKNUMBER: StaticSignature = StaticSignature(
&[],
Some(I64),
),
Static(
"_blocknumber",
);
pub const COINBASE: StaticSignature = StaticSignature(
&[I32],
None,
);
pub const DIFFICULTY: StaticSignature = StaticSignature(
&[I32],
None,
);
pub const GASLIMIT: StaticSignature = StaticSignature(
&[I32],
None,
);
pub const TIMESTAMP: StaticSignature = StaticSignature(
&[],
Some(I64),
),
Static(
"_difficulty",
);
pub const ADDRESS: StaticSignature = StaticSignature(
&[I32],
None,
),
Static(
"_gaslimit",
);
pub const SENDER: StaticSignature = StaticSignature(
&[I32],
None,
),
Static(
"_elog",
&[I32; 4],
);
pub const ORIGIN: StaticSignature = StaticSignature(
&[I32],
None,
),
);
// TODO: Get rid of it also somehow?
Static(
"_llvm_trap",
&[I32; 0],
None
),
pub const ELOG: StaticSignature = StaticSignature(
&[I32, I32, I32, I32],
None,
);
Static(
"_llvm_bswap_i64",
&[I64],
Some(I64)
),
];
pub fn native_bindings<'a>(runtime: &'a mut Runtime) -> interpreter::UserDefinedElements<'a, UserTrap> {
interpreter::UserDefinedElements {
executor: Some(runtime),
globals: ::std::collections::HashMap::new(),
functions: ::std::borrow::Cow::from(SIGNATURES),
impl Into<wasmi::Signature> for StaticSignature {
fn into(self) -> wasmi::Signature {
wasmi::Signature::new(self.0, self.1)
}
}
}
fn host(signature: signatures::StaticSignature, idx: usize) -> FuncRef {
FuncInstance::alloc_host(signature.into(), idx)
}
/// Import resolver for wasmi
/// Maps all functions that runtime support to the corresponding contract import
/// entries.
/// Also manages initial memory request from the runtime.
#[derive(Default)]
pub struct ImportResolver {
max_memory: u32,
memory: RefCell<Option<MemoryRef>>,
}
impl ImportResolver {
/// New import resolver with specifed maximum amount of inital memory (in wasm pages = 64kb)
pub fn with_limit(max_memory: u32) -> ImportResolver {
ImportResolver {
max_memory: max_memory,
memory: RefCell::new(None),
}
}
/// Returns memory that was instantiated during the contract module
/// start. If contract does not use memory at all, the dummy memory of length (0, 0)
/// will be created instead. So this method always returns memory instance
/// unless errored.
pub fn memory_ref(&self) -> MemoryRef {
{
let mut mem_ref = self.memory.borrow_mut();
if mem_ref.is_none() {
*mem_ref = Some(
MemoryInstance::alloc(0, Some(0)).expect("Memory allocation (0, 0) should not fail; qed")
);
}
}
self.memory.borrow().clone().expect("it is either existed or was created as (0, 0) above; qed")
}
/// Returns memory size module initially requested
pub fn memory_size(&self) -> Result<u32, Error> {
Ok(self.memory_ref().size())
}
}
impl wasmi::ModuleImportResolver for ImportResolver {
fn resolve_func(&self, field_name: &str, _signature: &Signature) -> Result<FuncRef, Error> {
let func_ref = match field_name {
"storage_read" => host(signatures::STORAGE_READ, ids::STORAGE_READ_FUNC),
"storage_write" => host(signatures::STORAGE_WRITE, ids::STORAGE_WRITE_FUNC),
"ret" => host(signatures::RET, ids::RET_FUNC),
"gas" => host(signatures::GAS, ids::GAS_FUNC),
"input_length" => host(signatures::INPUT_LENGTH, ids::INPUT_LENGTH_FUNC),
"fetch_input" => host(signatures::FETCH_INPUT, ids::FETCH_INPUT_FUNC),
"panic" => host(signatures::PANIC, ids::PANIC_FUNC),
"debug" => host(signatures::DEBUG, ids::DEBUG_FUNC),
"ccall" => host(signatures::CCALL, ids::CCALL_FUNC),
"dcall" => host(signatures::DCALL, ids::DCALL_FUNC),
"scall" => host(signatures::SCALL, ids::SCALL_FUNC),
"value" => host(signatures::VALUE, ids::VALUE_FUNC),
"create" => host(signatures::CREATE, ids::CREATE_FUNC),
"suicide" => host(signatures::SUICIDE, ids::SUICIDE_FUNC),
"blockhash" => host(signatures::BLOCKHASH, ids::BLOCKHASH_FUNC),
"blocknumber" => host(signatures::BLOCKNUMBER, ids::BLOCKNUMBER_FUNC),
"coinbase" => host(signatures::COINBASE, ids::COINBASE_FUNC),
"difficulty" => host(signatures::DIFFICULTY, ids::DIFFICULTY_FUNC),
"gaslimit" => host(signatures::GASLIMIT, ids::GASLIMIT_FUNC),
"timestamp" => host(signatures::TIMESTAMP, ids::TIMESTAMP_FUNC),
"address" => host(signatures::ADDRESS, ids::ADDRESS_FUNC),
"sender" => host(signatures::SENDER, ids::SENDER_FUNC),
"origin" => host(signatures::ORIGIN, ids::ORIGIN_FUNC),
"elog" => host(signatures::ELOG, ids::ELOG_FUNC),
_ => {
return Err(wasmi::Error::Instantiation(
format!("Export {} not found", field_name),
))
}
};
Ok(func_ref)
}
fn resolve_memory(
&self,
field_name: &str,
descriptor: &MemoryDescriptor,
) -> Result<MemoryRef, Error> {
if field_name == "memory" {
let effective_max = descriptor.maximum().unwrap_or(self.max_memory + 1);
if descriptor.initial() > self.max_memory || effective_max > self.max_memory
{
Err(Error::Instantiation("Module requested too much memory".to_owned()))
} else {
let mem = MemoryInstance::alloc(descriptor.initial(), descriptor.maximum())?;
*self.memory.borrow_mut() = Some(mem.clone());
Ok(mem)
}
} else {
Err(Error::Instantiation("Memory imported under unknown name".to_owned()))
}
}
}

View File

@@ -16,34 +16,30 @@
//! Wasm Interpreter
extern crate vm;
extern crate byteorder;
extern crate ethcore_logger;
extern crate ethcore_util as util;
extern crate ethcore_bigint as bigint;
#[macro_use] extern crate log;
extern crate ethcore_logger;
extern crate byteorder;
extern crate libc;
extern crate parity_wasm;
extern crate vm;
extern crate wasm_utils;
extern crate wasmi;
mod runtime;
mod ptr;
mod result;
#[cfg(test)]
mod tests;
mod env;
mod panic_payload;
const DEFAULT_STACK_SPACE: u32 = 5 * 1024 * 1024;
use parity_wasm::{interpreter, elements};
use parity_wasm::interpreter::ModuleInstanceInterface;
mod parser;
use vm::{GasLeft, ReturnData, ActionParams};
use self::runtime::{Runtime, RuntimeContext, UserTrap};
use wasmi::Error as InterpreterError;
pub use self::runtime::InterpreterError;
use runtime::{Runtime, RuntimeContext};
const DEFAULT_RESULT_BUFFER: usize = 1024;
use bigint::uint::U256;
/// Wrapped interpreter error
#[derive(Debug)]
@@ -61,139 +57,110 @@ impl From<Error> for vm::Error {
}
}
impl From<UserTrap> for vm::Error {
fn from(e: UserTrap) -> Self { e.into() }
}
/// Wasm interpreter instance
pub struct WasmInterpreter {
program: runtime::InterpreterProgramInstance,
result: Vec<u8>,
}
pub struct WasmInterpreter;
impl WasmInterpreter {
/// New wasm interpreter instance
pub fn new() -> Result<WasmInterpreter, Error> {
Ok(WasmInterpreter {
program: interpreter::ProgramInstance::new()?,
result: Vec::with_capacity(DEFAULT_RESULT_BUFFER),
})
impl From<runtime::Error> for vm::Error {
fn from(e: runtime::Error) -> Self {
vm::Error::Wasm(format!("Wasm runtime error: {:?}", e))
}
}
impl vm::Vm for WasmInterpreter {
fn exec(&mut self, params: ActionParams, ext: &mut vm::Ext) -> vm::Result<GasLeft> {
use parity_wasm::elements::Deserialize;
let (module, data) = parser::payload(&params, ext.schedule())?;
let code = params.code.expect("exec is only called on contract with code; qed");
let loaded_module = wasmi::Module::from_parity_wasm_module(module).map_err(Error)?;
trace!(target: "wasm", "Started wasm interpreter with code.len={:?}", code.len());
let instantiation_resolover = env::ImportResolver::with_limit(16);
let env_instance = self.program.module("env")
// prefer explicit panic here
.expect("Wasm program to contain env module");
let module_instance = wasmi::ModuleInstance::new(
&loaded_module,
&wasmi::ImportsBuilder::new().with_resolver("env", &instantiation_resolover)
).map_err(Error)?;
let env_memory = env_instance.memory(interpreter::ItemIndex::Internal(0))
// prefer explicit panic here
.expect("Linear memory to exist in wasm runtime");
let adjusted_gas = params.gas * U256::from(ext.schedule().wasm.opcodes_div) /
U256::from(ext.schedule().wasm.opcodes_mul);
if params.gas > ::std::u64::MAX.into() {
return Err(vm::Error::Wasm("Wasm interpreter cannot run contracts with gas >= 2^64".to_owned()));
if adjusted_gas > ::std::u64::MAX.into()
{
return Err(vm::Error::Wasm("Wasm interpreter cannot run contracts with gas (wasm adjusted) >= 2^64".to_owned()));
}
let mut runtime = Runtime::with_params(
ext,
env_memory,
DEFAULT_STACK_SPACE,
params.gas.low_u64(),
RuntimeContext {
address: params.address,
sender: params.sender,
origin: params.origin,
code_address: params.code_address,
value: params.value.value(),
},
&self.program,
);
let initial_memory = instantiation_resolover.memory_size().map_err(Error)?;
trace!(target: "wasm", "Contract requested {:?} pages of initial memory", initial_memory);
let (mut cursor, data_position) = match params.params_type {
vm::ParamsType::Embedded => {
let module_size = parity_wasm::peek_size(&*code);
(
::std::io::Cursor::new(&code[..module_size]),
module_size
)
},
vm::ParamsType::Separate => {
(::std::io::Cursor::new(&code[..]), 0)
},
};
let contract_module = wasm_utils::inject_gas_counter(
elements::Module::deserialize(
&mut cursor
).map_err(|err| {
vm::Error::Wasm(format!("Error deserializing contract code ({:?})", err))
})?,
runtime.gas_rules(),
);
let data_section_length = contract_module.data_section()
.map(|section| section.entries().iter().fold(0, |sum, entry| sum + entry.value().len()))
.unwrap_or(0)
as u64;
let static_segment_cost = data_section_length * runtime.ext().schedule().wasm.static_region as u64;
runtime.charge(|_| static_segment_cost).map_err(Error)?;
let d_ptr = {
match params.params_type {
vm::ParamsType::Embedded => {
runtime.write_descriptor(
if data_position < code.len() { &code[data_position..] } else { &[] }
).map_err(Error)?
let (gas_left, result) = {
let mut runtime = Runtime::with_params(
ext,
instantiation_resolover.memory_ref(),
// cannot overflow, checked above
adjusted_gas.low_u64(),
data.to_vec(),
RuntimeContext {
address: params.address,
sender: params.sender,
origin: params.origin,
code_address: params.code_address,
value: params.value.value(),
},
vm::ParamsType::Separate => {
runtime.write_descriptor(&params.data.unwrap_or_default())
.map_err(Error)?
}
}
};
);
{
let execution_params = runtime.execution_params()
.add_argument(interpreter::RuntimeValue::I32(d_ptr.as_raw() as i32));
// cannot overflow if static_region < 2^16,
// initial_memory ∈ [0..2^32)
// total_charge <- static_region * 2^32 * 2^16
// total_charge ∈ [0..2^64) if static_region ∈ [0..2^16)
// qed
assert!(runtime.schedule().wasm.initial_mem < 1 << 16);
runtime.charge(|s| initial_memory as u64 * s.wasm.initial_mem as u64)?;
let module_instance = self.program.add_module("contract", contract_module, Some(&execution_params.externals))
.map_err(|err| {
trace!(target: "wasm", "Error adding contract module: {:?}", err);
vm::Error::from(Error(err))
})?;
let module_instance = module_instance.run_start(&mut runtime).map_err(Error)?;
match module_instance.execute_export("_call", execution_params) {
match module_instance.invoke_export("call", &[], &mut runtime) {
Ok(_) => { },
Err(interpreter::Error::User(UserTrap::Suicide)) => { },
Err(InterpreterError::Host(boxed)) => {
match boxed.downcast_ref::<runtime::Error>() {
None => {
return Err(vm::Error::Wasm("Invalid user error used in interpreter".to_owned()));
}
Some(runtime_err) => {
match *runtime_err {
runtime::Error::Suicide => {
// Suicide uses trap to break execution
}
ref any_err => {
trace!(target: "wasm", "Error executing contract: {:?}", boxed);
return Err(vm::Error::from(Error::from(InterpreterError::Host(Box::new(any_err.clone())))));
}
}
}
}
},
Err(err) => {
trace!(target: "wasm", "Error executing contract: {:?}", err);
return Err(vm::Error::from(Error(err)))
return Err(vm::Error::from(Error::from(err)))
}
}
}
(
runtime.gas_left().expect("Cannot fail since it was not updated since last charge"),
runtime.into_result(),
)
};
let result = result::WasmResult::new(d_ptr);
if result.peek_empty(&*runtime.memory()).map_err(|e| Error(e))? {
let gas_left =
U256::from(gas_left) * U256::from(ext.schedule().wasm.opcodes_mul)
/ U256::from(ext.schedule().wasm.opcodes_div);
if result.is_empty() {
trace!(target: "wasm", "Contract execution result is empty.");
Ok(GasLeft::Known(runtime.gas_left()?.into()))
Ok(GasLeft::Known(gas_left))
} else {
self.result.clear();
// todo: use memory views to avoid copy
self.result.extend(result.pop(&*runtime.memory()).map_err(|e| Error(e.into()))?);
let len = self.result.len();
let len = result.len();
Ok(GasLeft::NeedsReturn {
gas_left: runtime.gas_left().map_err(|e| Error(e.into()))?.into(),
gas_left: gas_left,
data: ReturnData::new(
::std::mem::replace(&mut self.result, Vec::with_capacity(DEFAULT_RESULT_BUFFER)),
result,
0,
len,
),

View File

@@ -0,0 +1,89 @@
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! ActionParams parser for wasm
use vm;
use wasm_utils::{self, rules};
use parity_wasm::elements::{self, Deserialize};
use parity_wasm::peek_size;
fn gas_rules(schedule: &vm::Schedule) -> rules::Set {
rules::Set::new({
let mut vals = ::std::collections::HashMap::with_capacity(4);
vals.insert(rules::InstructionType::Load, schedule.wasm.mem as u32);
vals.insert(rules::InstructionType::Store, schedule.wasm.mem as u32);
vals.insert(rules::InstructionType::Div, schedule.wasm.div as u32);
vals.insert(rules::InstructionType::Mul, schedule.wasm.mul as u32);
vals
}).with_grow_cost(schedule.wasm.grow_mem)
}
/// Splits payload to code and data according to params.params_type, also
/// loads the module instance from payload and injects gas counter according
/// to schedule.
pub fn payload<'a>(params: &'a vm::ActionParams, schedule: &vm::Schedule)
-> Result<(elements::Module, &'a [u8]), vm::Error>
{
let code = match params.code {
Some(ref code) => &code[..],
None => { return Err(vm::Error::Wasm("Invalid wasm call".to_owned())); }
};
let (mut cursor, data_position) = match params.params_type {
vm::ParamsType::Embedded => {
let module_size = peek_size(&*code);
(
::std::io::Cursor::new(&code[..module_size]),
module_size
)
},
vm::ParamsType::Separate => {
(::std::io::Cursor::new(&code[..]), 0)
},
};
let deserialized_module = elements::Module::deserialize(
&mut cursor
).map_err(|err| {
vm::Error::Wasm(format!("Error deserializing contract code ({:?})", err))
})?;
if deserialized_module.memory_section().map_or(false, |ms| ms.entries().len() > 0) {
// According to WebAssembly spec, internal memory is hidden from embedder and should not
// be interacted with. So we disable this kind of modules at decoding level.
return Err(vm::Error::Wasm(format!("Malformed wasm module: internal memory")));
}
let contract_module = wasm_utils::inject_gas_counter(
deserialized_module,
&gas_rules(schedule),
);
let data = match params.params_type {
vm::ParamsType::Embedded => {
if data_position < code.len() { &code[data_position..] } else { &[] }
},
vm::ParamsType::Separate => {
match params.data {
Some(ref s) => &s[..],
None => &[]
}
}
};
Ok((contract_module, data))
}

View File

@@ -1,58 +0,0 @@
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Wasm bound-checked ptr
use super::runtime::{InterpreterMemoryInstance, InterpreterError, UserTrap};
/// Bound-checked wrapper for webassembly memory
pub struct WasmPtr(u32);
/// Error in bound check
#[derive(Debug)]
pub enum Error {
AccessViolation,
}
impl From<u32> for WasmPtr {
fn from(raw: u32) -> Self {
WasmPtr(raw)
}
}
impl From<Error> for InterpreterError {
fn from(_e: Error) -> Self {
UserTrap::MemoryAccessViolation.into()
}
}
impl WasmPtr {
// todo: use memory view when they are on
/// Check memory range and return data with given length starting from the current pointer value
pub fn slice(&self, len: u32, mem: &InterpreterMemoryInstance) -> Result<Vec<u8>, Error> {
mem.get(self.0, len as usize).map_err(|_| Error::AccessViolation)
}
// todo: maybe 2gb limit can be enhanced
/// Convert i32 from wasm stack to the wrapped pointer
pub fn from_i32(raw_ptr: i32) -> Result<Self, Error> {
if raw_ptr < 0 { return Err(Error::AccessViolation); }
Ok(WasmPtr(raw_ptr as u32))
}
/// Return pointer raw value
pub fn as_raw(&self) -> u32 { self.0 }
}

View File

@@ -1,49 +0,0 @@
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Wasm evm results helper
use byteorder::{LittleEndian, ByteOrder};
use super::ptr::WasmPtr;
use super::runtime::{InterpreterError, InterpreterMemoryInstance};
/// Wrapper for wasm contract call result
pub struct WasmResult {
ptr: WasmPtr,
}
impl WasmResult {
/// New call result from given ptr
pub fn new(descriptor_ptr: WasmPtr) -> WasmResult {
WasmResult { ptr: descriptor_ptr }
}
/// Check if the result contains any data
pub fn peek_empty(&self, mem: &InterpreterMemoryInstance) -> Result<bool, InterpreterError> {
let result_len = LittleEndian::read_u32(&self.ptr.slice(16, mem)?[12..16]);
Ok(result_len == 0)
}
/// Consume the result ptr and return the actual data from wasm linear memory
pub fn pop(self, mem: &InterpreterMemoryInstance) -> Result<Vec<u8>, InterpreterError> {
let result_ptr = LittleEndian::read_u32(&self.ptr.slice(16, mem)?[8..12]);
let result_len = LittleEndian::read_u32(&self.ptr.slice(16, mem)?[12..16]);
trace!(target: "wasm", "contract result: {} bytes at @{}", result_len, result_ptr);
Ok(mem.get(result_ptr, result_len as usize)?)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -31,6 +31,34 @@ macro_rules! load_sample {
}
}
macro_rules! reqrep_test {
($name: expr, $input: expr) => {
reqrep_test!($name, $input, vm::EnvInfo::default(), HashMap::new())
};
($name: expr, $input: expr, $info: expr, $block_hashes: expr) => {
{
::ethcore_logger::init_log();
let code = load_sample!($name);
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(Arc::new(code));
params.data = Some($input);
let mut fake_ext = FakeExt::new();
fake_ext.info = $info;
fake_ext.blockhashes = $block_hashes;
let mut interpreter = wasm_interpreter();
interpreter.exec(params, &mut fake_ext)
.map(|result| match result {
GasLeft::Known(_) => { panic!("Test is expected to return payload to check"); },
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
})
}
};
}
fn test_finalize(res: Result<GasLeft, vm::Error>) -> Result<U256, vm::Error> {
match res {
Ok(GasLeft::Known(gas)) => Ok(gas),
@@ -40,7 +68,7 @@ fn test_finalize(res: Result<GasLeft, vm::Error>) -> Result<U256, vm::Error> {
}
fn wasm_interpreter() -> WasmInterpreter {
WasmInterpreter::new().expect("wasm interpreter to create without errors")
WasmInterpreter
}
/// Empty contract does almost nothing except producing 1 (one) local node debug log message
@@ -60,7 +88,7 @@ fn empty() {
test_finalize(interpreter.exec(params, &mut ext)).unwrap()
};
assert_eq!(gas_left, U256::from(96_678));
assert_eq!(gas_left, U256::from(98462));
}
// This test checks if the contract deserializes payload header properly.
@@ -112,7 +140,7 @@ fn logger() {
U256::from(1_000_000_000),
"Logger sets 0x04 key to the trasferred value"
);
assert_eq!(gas_left, U256::from(15_860));
assert_eq!(gas_left, U256::from(17_578));
}
// This test checks if the contract can allocate memory and pass pointer to the result stream properly.
@@ -147,7 +175,7 @@ fn identity() {
sender,
"Idenity test contract does not return the sender passed"
);
assert_eq!(gas_left, U256::from(96_540));
assert_eq!(gas_left, U256::from(98_408));
}
// Dispersion test sends byte array and expect the contract to 'disperse' the original elements with
@@ -156,6 +184,8 @@ fn identity() {
// This also tests byte-perfect memory allocation and in/out ptr lifecycle.
#[test]
fn dispersion() {
::ethcore_logger::init_log();
let code = load_sample!("dispersion.wasm");
let mut params = ActionParams::default();
@@ -175,12 +205,11 @@ fn dispersion() {
}
};
assert_eq!(
result,
vec![0u8, 0, 125, 11, 197, 7, 255, 8, 19, 0]
);
assert_eq!(gas_left, U256::from(96_116));
assert_eq!(gas_left, U256::from(93_972));
}
#[test]
@@ -208,7 +237,7 @@ fn suicide_not() {
result,
vec![0u8]
);
assert_eq!(gas_left, U256::from(96_461));
assert_eq!(gas_left, U256::from(94_970));
}
#[test]
@@ -240,7 +269,7 @@ fn suicide() {
};
assert!(ext.suicides.contains(&refund));
assert_eq!(gas_left, U256::from(96_429));
assert_eq!(gas_left, U256::from(94_933));
}
#[test]
@@ -270,7 +299,7 @@ fn create() {
assert!(ext.calls.contains(
&FakeCall {
call_type: FakeCallType::Create,
gas: U256::from(62_545),
gas: U256::from(60_917),
sender_address: None,
receive_address: None,
value: Some(1_000_000_000.into()),
@@ -278,7 +307,7 @@ fn create() {
code_address: None,
}
));
assert_eq!(gas_left, U256::from(62_538));
assert_eq!(gas_left, U256::from(60_903));
}
#[test]
@@ -322,7 +351,7 @@ fn call_msg() {
}
));
assert_eq!(gas_left, U256::from(95_699));
assert_eq!(gas_left, U256::from(93_511));
}
#[test]
@@ -367,7 +396,7 @@ fn call_code() {
// siphash result
let res = LittleEndian::read_u32(&result[..]);
assert_eq!(res, 4198595614);
assert_eq!(gas_left, U256::from(90_550));
assert_eq!(gas_left, U256::from(92_381));
}
#[test]
@@ -415,7 +444,7 @@ fn call_static() {
let res = LittleEndian::read_u32(&result[..]);
assert_eq!(res, 317632590);
assert_eq!(gas_left, U256::from(90_550));
assert_eq!(gas_left, U256::from(92_381));
}
// Realloc test
@@ -438,13 +467,37 @@ fn realloc() {
}
};
assert_eq!(result, vec![0u8; 2]);
assert_eq!(gas_left, U256::from(96_445));
assert_eq!(gas_left, U256::from(94_352));
}
#[test]
fn alloc() {
let code = load_sample!("alloc.wasm");
let mut params = ActionParams::default();
params.gas = U256::from(10_000_000);
params.code = Some(Arc::new(code));
params.data = Some(vec![0u8]);
let mut ext = FakeExt::new();
let (gas_left, result) = {
let mut interpreter = wasm_interpreter();
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
match result {
GasLeft::Known(_) => { panic!("alloc test should return payload"); },
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
}
};
assert_eq!(result, vec![5u8; 1024*450]);
assert_eq!(gas_left, U256::from(6_506_844));
}
// Tests that contract's ability to read from a storage
// Test prepopulates address into storage, than executes a contract which read that address from storage and write this address into result
#[test]
fn storage_read() {
::ethcore_logger::init_log();
let code = load_sample!("storage_read.wasm");
let address: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
@@ -464,7 +517,7 @@ fn storage_read() {
};
assert_eq!(Address::from(&result[12..32]), address);
assert_eq!(gas_left, U256::from(96_463));
assert_eq!(gas_left, U256::from(98_298));
}
// Tests keccak calculation
@@ -490,124 +543,7 @@ fn keccak() {
};
assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
assert_eq!(gas_left, U256::from(81_067));
}
// memcpy test.
#[test]
fn memcpy() {
::ethcore_logger::init_log();
let code = load_sample!("mem.wasm");
let mut test_payload = Vec::with_capacity(8192);
for i in 0..8192 {
test_payload.push((i % 255) as u8);
}
let mut data = vec![0u8];
data.extend(&test_payload);
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(Arc::new(code));
params.data = Some(data);
let mut ext = FakeExt::new();
let (gas_left, result) = {
let mut interpreter = wasm_interpreter();
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
match result {
GasLeft::Known(_) => { panic!("mem should return payload"); },
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
}
};
assert_eq!(result, test_payload);
assert_eq!(gas_left, U256::from(71_940));
}
// memmove test.
#[test]
fn memmove() {
::ethcore_logger::init_log();
let code = load_sample!("mem.wasm");
let mut test_payload = Vec::with_capacity(8192);
for i in 0..8192 {
test_payload.push((i % 255) as u8);
}
let mut data = vec![1u8];
data.extend(&test_payload);
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(Arc::new(code));
params.data = Some(data);
let mut ext = FakeExt::new();
let (gas_left, result) = {
let mut interpreter = wasm_interpreter();
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
match result {
GasLeft::Known(_) => { panic!("mem should return payload"); },
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
}
};
assert_eq!(result, test_payload);
assert_eq!(gas_left, U256::from(71_940));
}
// memset test
#[test]
fn memset() {
::ethcore_logger::init_log();
let code = load_sample!("mem.wasm");
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(Arc::new(code));
params.data = Some(vec![2u8, 228u8]);
let mut ext = FakeExt::new();
let (gas_left, result) = {
let mut interpreter = wasm_interpreter();
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
match result {
GasLeft::Known(_) => { panic!("mem should return payload"); },
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
}
};
assert_eq!(result, vec![228u8; 8192]);
assert_eq!(gas_left, U256::from(71_921));
}
macro_rules! reqrep_test {
($name: expr, $input: expr) => {
reqrep_test!($name, $input, vm::EnvInfo::default(), HashMap::new())
};
($name: expr, $input: expr, $info: expr, $block_hashes: expr) => {
{
::ethcore_logger::init_log();
let code = load_sample!($name);
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(Arc::new(code));
params.data = Some($input);
let mut fake_ext = FakeExt::new();
fake_ext.info = $info;
fake_ext.blockhashes = $block_hashes;
let mut interpreter = wasm_interpreter();
interpreter.exec(params, &mut fake_ext)
.map(|result| match result {
GasLeft::Known(_) => { panic!("Test is expected to return payload to check"); },
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
})
}
};
assert_eq!(gas_left, U256::from(84_223));
}
// math_* tests check the ability of wasm contract to perform big integer operations
@@ -636,7 +572,7 @@ fn math_add() {
U256::from_dec_str("1888888888888888888888888888887").unwrap(),
(&result[..]).into()
);
assert_eq!(gas_left, U256::from(95_384));
assert_eq!(gas_left, U256::from(93_818));
}
// multiplication
@@ -658,7 +594,7 @@ fn math_mul() {
U256::from_dec_str("888888888888888888888888888887111111111111111111111111111112").unwrap(),
(&result[..]).into()
);
assert_eq!(gas_left, U256::from(94_374));
assert_eq!(gas_left, U256::from(93_304));
}
// subtraction
@@ -680,7 +616,7 @@ fn math_sub() {
U256::from_dec_str("111111111111111111111111111111").unwrap(),
(&result[..]).into()
);
assert_eq!(gas_left, U256::from(95_372));
assert_eq!(gas_left, U256::from(93_831));
}
// subtraction with overflow
@@ -722,7 +658,54 @@ fn math_div() {
U256::from_dec_str("1125000").unwrap(),
(&result[..]).into()
);
assert_eq!(gas_left, U256::from(88_356));
assert_eq!(gas_left, U256::from(90_607));
}
#[test]
fn storage_metering() {
::ethcore_logger::init_log();
// #1
let mut ext = FakeExt::new();
let code = Arc::new(load_sample!("setter.wasm"));
let address: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
let mut params = ActionParams::default();
params.address = address.clone();
params.gas = U256::from(100_000);
params.code = Some(code.clone());
params.data = Some(vec![
0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b,
]);
let gas_left = {
let mut interpreter = wasm_interpreter();
test_finalize(interpreter.exec(params, &mut ext)).unwrap()
};
// 0 -> not 0
assert_eq!(gas_left, U256::from(74_410));
// #2
let mut params = ActionParams::default();
params.address = address.clone();
params.gas = U256::from(100_000);
params.code = Some(code.clone());
params.data = Some(vec![
0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
0x6b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b,
]);
let gas_left = {
let mut interpreter = wasm_interpreter();
test_finalize(interpreter.exec(params, &mut ext)).unwrap()
};
// not 0 -> not 0
assert_eq!(gas_left, U256::from(89_410));
}
// This test checks the ability of wasm contract to invoke
@@ -810,7 +793,7 @@ fn externs() {
"Gas limit requested and returned does not match"
);
assert_eq!(gas_left, U256::from(95_321));
assert_eq!(gas_left, U256::from(92_089));
}
#[test]
@@ -836,7 +819,7 @@ fn embedded_keccak() {
};
assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
assert_eq!(gas_left, U256::from(81_067));
assert_eq!(gas_left, U256::from(84_223));
}
/// This test checks the correctness of log extern
@@ -871,5 +854,5 @@ fn events() {
assert_eq!(&log_entry.data, b"gnihtemos");
assert_eq!(&result, b"gnihtemos");
assert_eq!(gas_left, U256::from(79_206));
assert_eq!(gas_left, U256::from(81_235));
}

View File

@@ -15,6 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::{fs, io};
use std::io::Write;
use std::path::{PathBuf, Path};
use std::collections::HashMap;
use time;
@@ -152,31 +153,39 @@ impl<T> DiskDirectory<T> where T: KeyFileManager {
)
}
/// insert account with given file name
pub fn insert_with_filename(&self, account: SafeAccount, filename: String) -> Result<SafeAccount, Error> {
/// insert account with given filename. if the filename is a duplicate of any stored account and dedup is set to
/// true, a random suffix is appended to the filename.
pub fn insert_with_filename(&self, account: SafeAccount, mut filename: String, dedup: bool) -> Result<SafeAccount, Error> {
// path to keyfile
let mut keyfile_path = self.path.join(filename.as_str());
// check for duplicate filename and append random suffix
if dedup && keyfile_path.exists() {
let suffix = ::random::random_string(4);
filename.push_str(&format!("-{}", suffix));
keyfile_path.set_file_name(&filename);
}
// update account filename
let original_account = account.clone();
let mut account = account;
account.filename = Some(filename.clone());
account.filename = Some(filename);
{
// Path to keyfile
let mut keyfile_path = self.path.clone();
keyfile_path.push(filename.as_str());
// save the file
let mut file = fs::File::create(&keyfile_path)?;
if let Err(err) = self.key_manager.write(original_account, &mut file).map_err(|e| Error::Custom(format!("{:?}", e))) {
drop(file);
fs::remove_file(keyfile_path).expect("Expected to remove recently created file");
return Err(err);
}
// write key content
self.key_manager.write(original_account, &mut file).map_err(|e| Error::Custom(format!("{:?}", e)))?;
file.flush()?;
if let Err(_) = restrict_permissions_to_owner(keyfile_path.as_path()) {
drop(file);
fs::remove_file(keyfile_path).expect("Expected to remove recently created file");
return Err(Error::Io(io::Error::last_os_error()));
}
file.sync_all()?;
}
Ok(account)
@@ -199,17 +208,13 @@ impl<T> KeyDirectory for DiskDirectory<T> where T: KeyFileManager {
fn update(&self, account: SafeAccount) -> Result<SafeAccount, Error> {
// Disk store handles updates correctly iff filename is the same
self.insert(account)
let filename = account_filename(&account);
self.insert_with_filename(account, filename, false)
}
fn insert(&self, account: SafeAccount) -> Result<SafeAccount, Error> {
// build file path
let filename = account.filename.as_ref().cloned().unwrap_or_else(|| {
let timestamp = time::strftime("%Y-%m-%dT%H-%M-%S", &time::now_utc()).expect("Time-format string is valid.");
format!("UTC--{}Z--{}", timestamp, Uuid::from(account.id))
});
self.insert_with_filename(account, filename)
let filename = account_filename(&account);
self.insert_with_filename(account, filename, true)
}
fn remove(&self, account: &SafeAccount) -> Result<(), Error> {
@@ -285,6 +290,14 @@ impl KeyFileManager for DiskKeyFileManager {
}
}
fn account_filename(account: &SafeAccount) -> String {
// build file path
account.filename.clone().unwrap_or_else(|| {
let timestamp = time::strftime("%Y-%m-%dT%H-%M-%S", &time::now_utc()).expect("Time-format string is valid.");
format!("UTC--{}Z--{}", timestamp, Uuid::from(account.id))
})
}
#[cfg(test)]
mod test {
extern crate tempdir;
@@ -316,6 +329,38 @@ mod test {
let _ = fs::remove_dir_all(dir);
}
#[test]
fn should_handle_duplicate_filenames() {
// given
let mut dir = env::temp_dir();
dir.push("ethstore_should_handle_duplicate_filenames");
let keypair = Random.generate().unwrap();
let password = "hello world";
let directory = RootDiskDirectory::create(dir.clone()).unwrap();
// when
let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned());
let filename = "test".to_string();
let dedup = true;
directory.insert_with_filename(account.clone(), "foo".to_string(), dedup).unwrap();
let file1 = directory.insert_with_filename(account.clone(), filename.clone(), dedup).unwrap().filename.unwrap();
let file2 = directory.insert_with_filename(account.clone(), filename.clone(), dedup).unwrap().filename.unwrap();
let file3 = directory.insert_with_filename(account.clone(), filename.clone(), dedup).unwrap().filename.unwrap();
// then
// the first file should have the original names
assert_eq!(file1, filename);
// the following duplicate files should have a suffix appended
assert!(file2 != file3);
assert_eq!(file2.len(), filename.len() + 5);
assert_eq!(file3.len(), filename.len() + 5);
// cleanup
let _ = fs::remove_dir_all(dir);
}
#[test]
fn should_manage_vaults() {
// given

View File

@@ -106,7 +106,7 @@ impl VaultDiskDirectory {
fn copy_to_vault(&self, vault: &VaultDiskDirectory) -> Result<(), Error> {
for account in self.load()? {
let filename = account.filename.clone().expect("self is instance of DiskDirectory; DiskDirectory fills filename in load; qed");
vault.insert_with_filename(account, filename)?;
vault.insert_with_filename(account, filename, true)?;
}
Ok(())

View File

@@ -166,9 +166,14 @@ impl SecretStore for EthStore {
self.insert_account(vault, keypair.secret().clone(), password)
}
fn import_wallet(&self, vault: SecretVaultRef, json: &[u8], password: &str) -> Result<StoreAccountRef, Error> {
fn import_wallet(&self, vault: SecretVaultRef, json: &[u8], password: &str, gen_id: bool) -> Result<StoreAccountRef, Error> {
let json_keyfile = json::KeyFile::load(json).map_err(|_| Error::InvalidKeyFile("Invalid JSON format".to_owned()))?;
let mut safe_account = SafeAccount::from_file(json_keyfile, None);
if gen_id {
safe_account.id = Random::random();
}
let secret = safe_account.crypto.secret(password).map_err(|_| Error::InvalidPassword)?;
safe_account.address = KeyPair::from_secret(secret)?.address();
self.store.import(vault, safe_account)

View File

@@ -116,7 +116,7 @@ pub trait SecretStore: SimpleSecretStore {
/// Imports presale wallet
fn import_presale(&self, vault: SecretVaultRef, json: &[u8], password: &str) -> Result<StoreAccountRef, Error>;
/// Imports existing JSON wallet
fn import_wallet(&self, vault: SecretVaultRef, json: &[u8], password: &str) -> Result<StoreAccountRef, Error>;
fn import_wallet(&self, vault: SecretVaultRef, json: &[u8], password: &str, gen_id: bool) -> Result<StoreAccountRef, Error>;
/// Copies account between stores and vaults.
fn copy_account(&self, new_store: &SimpleSecretStore, new_vault: SecretVaultRef, account: &StoreAccountRef, password: &str, new_password: &str) -> Result<(), Error>;
/// Checks if password matches given account.

View File

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

View File

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

View File

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

View File

@@ -10,7 +10,7 @@
!define DESCRIPTION "Fast, light, robust Ethereum implementation"
!define VERSIONMAJOR 1
!define VERSIONMINOR 9
!define VERSIONBUILD 1
!define VERSIONBUILD 3
!define ARGS ""
!define FIRST_START_ARGS "--mode=passive ui"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -95,7 +95,7 @@ impl ParityAccounts for ParityAccountsClient {
let store = self.account_provider()?;
store.import_presale(json.as_bytes(), &pass)
.or_else(|_| store.import_wallet(json.as_bytes(), &pass))
.or_else(|_| store.import_wallet(json.as_bytes(), &pass, true))
.map(Into::into)
.map_err(|e| errors::account("Could not create account.", e))
}

View File

@@ -480,7 +480,7 @@ fn should_export_account() {
// given
let tester = setup();
let wallet = r#"{"id":"6a186c80-7797-cff2-bc2e-7c1d6a6cc76e","version":3,"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"a1c6ff99070f8032ca1c4e8add006373"},"ciphertext":"df27e3db64aa18d984b6439443f73660643c2d119a6f0fa2fa9a6456fc802d75","kdf":"pbkdf2","kdfparams":{"c":10240,"dklen":32,"prf":"hmac-sha256","salt":"ddc325335cda5567a1719313e73b4842511f3e4a837c9658eeb78e51ebe8c815"},"mac":"3dc888ae79cbb226ff9c455669f6cf2d79be72120f2298f6cb0d444fddc0aa3d"},"address":"0042e5d2a662eeaca8a7e828c174f98f35d8925b","name":"parity-export-test","meta":"{\"passwordHint\":\"parity-export-test\",\"timestamp\":1490017814987}"}"#;
tester.accounts.import_wallet(wallet.as_bytes(), "parity-export-test").unwrap();
tester.accounts.import_wallet(wallet.as_bytes(), "parity-export-test", false).unwrap();
let accounts = tester.accounts.accounts().unwrap();
assert_eq!(accounts.len(), 1);
@@ -501,6 +501,26 @@ fn should_export_account() {
assert_eq!(result, Some(response.into()));
}
#[test]
fn should_import_wallet() {
let tester = setup();
let id = "6a186c80-7797-cff2-bc2e-7c1d6a6cc76e";
let request = r#"{"jsonrpc":"2.0","method":"parity_newAccountFromWallet","params":["{\"id\":\"<ID>\",\"version\":3,\"crypto\":{\"cipher\":\"aes-128-ctr\",\"cipherparams\":{\"iv\":\"478736fb55872c1baf01b27b1998c90b\"},\"ciphertext\":\"fe5a63cc0055d7b0b3b57886f930ad9b63f48950d1348145d95996c41e05f4e0\",\"kdf\":\"pbkdf2\",\"kdfparams\":{\"c\":10240,\"dklen\":32,\"prf\":\"hmac-sha256\",\"salt\":\"658436d6738a19731149a98744e5cf02c8d5aa1f8e80c1a43cc9351c70a984e4\"},\"mac\":\"c7384b26ecf25539d942030230062af9b69de5766cbcc4690bffce1536644631\"},\"address\":\"00bac56a8a27232baa044c03f43bf3648c961735\",\"name\":\"hello world\",\"meta\":\"{}\"}", "himom"],"id":1}"#;
let request = request.replace("<ID>", id);
let response = r#"{"jsonrpc":"2.0","result":"0x00bac56a8a27232baa044c03f43bf3648c961735","id":1}"#;
let res = tester.io.handle_request_sync(&request).unwrap();
assert_eq!(res, response);
let account_meta = tester.accounts.account_meta("0x00bac56a8a27232baa044c03f43bf3648c961735".into()).unwrap();
let account_uuid: String = account_meta.uuid.unwrap().into();
// the RPC should import the account with a new id
assert!(account_uuid != id);
}
#[test]
fn should_sign_message() {
let tester = setup();

View File

@@ -1,9 +1,12 @@
#!/bin/bash
set -e # fail on any error
set -u # treat unset variables as error
cargo build -j $(nproc) --release --features final $CARGOFLAGS
git clone https://github.com/paritytech/parity-import-tests
cp target/release/parity parity-import-tests/aura/parity
cd parity-import-tests/aura
echo "Start Aura test"
parity import blocks.rlp --chain chain.json
parity restore snap --chain chain.json
./parity import blocks.rlp --chain chain.json
./parity restore snap --chain chain.json
echo "Aura test complete"

View File

@@ -2,16 +2,18 @@
set -e # fail on any error
set -u # treat unset variables as error
#ARGUMENTS: 1. BUILD_PLATFORM (target for binaries) 2. PLATFORM (target for cargo) 3. ARC (architecture) 4. & 5. CC & CXX flags
#ARGUMENTS: 1. BUILD_PLATFORM (target for binaries) 2. PLATFORM (target for cargo) 3. ARC (architecture) 4. & 5. CC & CXX flags 6. binary identifier
BUILD_PLATFORM=$1
PLATFORM=$2
ARC=$3
CC=$4
CXX=$5
VER="$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")"
IDENT=$6
VER="$(grep -m 1 "version =" Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")"
S3WIN=""
echo "--------------------"
echo "Build for platform: " $BUILD_PLATFORM
echo "Build identifier: " $IDENT
echo "Cargo target: " $PLATFORM
echo "CC&CXX flags: " $CC ", " $CXX
echo "Architecture: " $ARC
@@ -20,6 +22,14 @@ echo "Parity version: " $VER
echo "Branch: " $CI_BUILD_REF_NAME
echo "--------------------"
echo "Rhash version:"
# NOTE for md5 and sha256 we want to display filename as well
# hence we use --* instead of -p *
MD5_BIN="rhash --md5"
SHA256_BIN="rhash --sha256"
# NOTE For SHA3 we need only hash (hence -p)
SHA3_BIN="rhash -p %{sha3-256}"
set_env () {
echo "Set ENVIROMENT"
export HOST_CC=gcc
@@ -50,21 +60,34 @@ build () {
echo "Build ethkey-cli:"
cargo build --target $PLATFORM --release -p ethkey-cli
}
strip_md5 () {
strip_binaries () {
echo "Strip binaries:"
$STRIP_BIN -v target/$PLATFORM/release/parity
$STRIP_BIN -v target/$PLATFORM/release/parity-evm
$STRIP_BIN -v target/$PLATFORM/release/ethstore
$STRIP_BIN -v target/$PLATFORM/release/ethkey;
export SHA3=$(rhash --sha3-256 target/$PLATFORM/release/parity -p %h)
}
calculate_checksums () {
echo "Checksum calculation:"
rhash --version
rm -rf *.md5
export SHA3=$(rhash --sha3-256 target/$PLATFORM/release/parity -p %h)
echo "Parity file SHA3:" $SHA3
md5sum target/$PLATFORM/release/parity > parity.md5
md5sum target/$PLATFORM/release/parity-evm > parity-evm.md5
md5sum target/$PLATFORM/release/ethstore > ethstore.md5
md5sum target/$PLATFORM/release/ethkey > ethkey.md5
rm -rf *.sha256
export SHA3="$($SHA3_BIN target/$PLATFORM/release/parity$S3WIN)"
# NOTE rhash 1.3.1 doesnt support keccak, workaround
if [ "$SHA3" == "%{sha3-256}" ]; then
export SHA3="$(target/$PLATFORM/release/parity$S3WIN tools hash target/$PLATFORM/release/parity$S3WIN)"
fi
echo "Parity file SHA3: $SHA3"
$MD5_BIN target/$PLATFORM/release/parity$S3WIN > parity$S3WIN.md5
$SHA256_BIN target/$PLATFORM/release/parity$S3WIN > parity$S3WIN.sha256
$MD5_BIN target/$PLATFORM/release/parity-evm$S3WIN > parity-evm$S3WIN.md5
$SHA256_BIN target/$PLATFORM/release/parity-evm$S3WIN > parity-evm$S3WIN.sha256
$MD5_BIN target/$PLATFORM/release/ethstore$S3WIN > ethstore$S3WIN.md5
$SHA256_BIN target/$PLATFORM/release/ethstore$S3WIN > ethstore$S3WIN.sha256
$MD5_BIN target/$PLATFORM/release/ethkey$S3WIN > ethkey$S3WIN.md5
$SHA256_BIN target/$PLATFORM/release/ethkey$S3WIN > ethkey$S3WIN.sha256
}
make_deb () {
rm -rf deb
@@ -98,8 +121,9 @@ make_deb () {
cp target/$PLATFORM/release/parity-evm deb/usr/bin/parity-evm
cp target/$PLATFORM/release/ethstore deb/usr/bin/ethstore
cp target/$PLATFORM/release/ethkey deb/usr/bin/ethkey
dpkg-deb -b deb "parity_"$VER"_"$ARC".deb"
md5sum "parity_"$VER"_"$ARC".deb" > "parity_"$VER"_"$ARC".deb.md5"
dpkg-deb -b deb "parity_"$VER"_"$IDENT"_"$ARC".deb"
$MD5_BIN "parity_"$VER"_"$IDENT"_"$ARC".deb" > "parity_"$VER"_"$IDENT"_"$ARC".deb.md5"
$SHA256_BIN "parity_"$VER"_"$IDENT"_"$ARC".deb" > "parity_"$VER"_"$IDENT"_"$ARC".deb.sha256"
}
make_rpm () {
rm -rf /install
@@ -108,9 +132,12 @@ make_rpm () {
cp target/$PLATFORM/release/parity-evm /install/usr/bin/parity-evm
cp target/$PLATFORM/release/ethstore /install/usr/bin/ethstore
cp target/$PLATFORM/release/ethkey /install/usr/bin/ethkey
rm -rf "parity-"$VER"-1."$ARC".rpm" || true
fpm -s dir -t rpm -n parity -v $VER --epoch 1 --license GPLv3 -d openssl --provides parity --url https://parity.io --vendor "Parity Technologies" -a x86_64 -m "<devops@parity.io>" --description "Ethereum network client by Parity Technologies" -C /install/
cp "parity-"$VER"-1."$ARC".rpm" "parity_"$VER"_"$ARC".rpm"
md5sum "parity_"$VER"_"$ARC".rpm" > "parity_"$VER"_"$ARC".rpm.md5"
cp "parity-"$VER"-1."$ARC".rpm" "parity_"$VER"_"$IDENT"_"$ARC".rpm"
$MD5_BIN "parity_"$VER"_"$IDENT"_"$ARC".rpm" > "parity_"$VER"_"$IDENT"_"$ARC".rpm.md5"
$SHA256_BIN "parity_"$VER"_"$IDENT"_"$ARC".rpm" > "parity_"$VER"_"$IDENT"_"$ARC".rpm.sha256"
}
make_pkg () {
echo "make PKG"
@@ -123,19 +150,14 @@ make_pkg () {
cd ..
packagesbuild -v mac/Parity.pkgproj
productsign --sign 'Developer ID Installer: PARITY TECHNOLOGIES LIMITED (P2PX3JU8FT)' target/release/Parity\ Ethereum.pkg target/release/Parity\ Ethereum-signed.pkg
mv target/release/Parity\ Ethereum-signed.pkg "parity_"$VER"_"$ARC".pkg"
md5sum "parity_"$VER"_"$ARC"."$EXT >> "parity_"$VER"_"$ARC".pkg.md5"
mv target/release/Parity\ Ethereum-signed.pkg "parity_"$VER"_"$IDENT"_"$ARC".pkg"
$MD5_BIN "parity_"$VER"_"$IDENT"_"$ARC"."$EXT >> "parity_"$VER"_"$IDENT"_"$ARC".pkg.md5"
$SHA256_BIN "parity_"$VER"_"$IDENT"_"$ARC"."$EXT >> "parity_"$VER"_"$IDENT"_"$ARC".pkg.sha256"
}
sign_exe () {
./sign.cmd $keyfile $certpass "target/$PLATFORM/release/parity.exe"
}
make_exe () {
./sign.cmd $keyfile $certpass "target/$PLATFORM/release/parity.exe"
SHA3=$(rhash --sha3-256 target/$PLATFORM/release/parity.exe -p %h)
echo "Checksum calculation:"
rm -rf *.md5
echo "Parity file SHA3:" $SHA3
rhash --md5 target/$PLATFORM/release/parity.exe -p %h > parity.exe.md5
rhash --md5 target/$PLATFORM/release/parity-evm.exe -p %h > parity-evm.exe.md5
rhash --md5 target/$PLATFORM/release/ethstore.exe -p %h > ethstore.exe.md5
rhash --md5 target/$PLATFORM/release/ethkey.exe -p %h > ethkey.exe.md5
./msbuild.cmd
./sign.cmd $keyfile $certpass windows/ptray/x64/release/ptray.exe
cd nsis
@@ -143,9 +165,10 @@ make_exe () {
echo "makensis.exe installer.nsi" > nsis.cmd
./nsis.cmd
cd ..
cp nsis/installer.exe "parity_"$VER"_"$ARC"."$EXT
./sign.cmd $keyfile $certpass "parity_"$VER"_"$ARC"."$EXT
rhash --md5 "parity_"$VER"_"$ARC"."$EXT -p %h > "parity_"$VER"_"$ARC"."$EXT".md5"
cp nsis/installer.exe "parity_"$VER"_"$IDENT"_"$ARC"."$EXT
./sign.cmd $keyfile $certpass "parity_"$VER"_"$IDENT"_"$ARC"."$EXT
$MD5_BIN "parity_"$VER"_"$IDENT"_"$ARC"."$EXT -p %h > "parity_"$VER"_"$IDENT"_"$ARC"."$EXT".md5"
$SHA256_BIN "parity_"$VER"_"$IDENT"_"$ARC"."$EXT -p %h > "parity_"$VER"_"$IDENT"_"$ARC"."$EXT".sha256"
}
push_binaries () {
echo "Push binaries to AWS S3"
@@ -160,25 +183,36 @@ push_binaries () {
aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/$BUILD_PLATFORM
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/parity$S3WIN --body target/$PLATFORM/release/parity$S3WIN
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/parity$S3WIN.md5 --body parity$S3WIN.md5
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/parity$S3WIN.sha256 --body parity$S3WIN.sha256
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/parity-evm$S3WIN --body target/$PLATFORM/release/parity-evm$S3WIN
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/parity-evm$S3WIN.md5 --body parity-evm$S3WIN.md5
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/parity-evm$S3WIN.sha256 --body parity-evm$S3WIN.sha256
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/ethstore$S3WIN --body target/$PLATFORM/release/ethstore$S3WIN
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/ethstore$S3WIN.md5 --body ethstore$S3WIN.md5
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/ethstore$S3WIN.sha256 --body ethstore$S3WIN.sha256
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/ethkey$S3WIN --body target/$PLATFORM/release/ethkey$S3WIN
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/ethkey$S3WIN.md5 --body ethkey$S3WIN.md5
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/"parity_"$VER"_"$ARC"."$EXT --body "parity_"$VER"_"$ARC"."$EXT
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/"parity_"$VER"_"$ARC"."$EXT".md5" --body "parity_"$VER"_"$ARC"."$EXT".md5"
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/ethkey$S3WIN.sha256 --body ethkey$S3WIN.sha256
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/"parity_"$VER"_"$IDENT"_"$ARC"."$EXT --body "parity_"$VER"_"$IDENT"_"$ARC"."$EXT
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/"parity_"$VER"_"$IDENT"_"$ARC"."$EXT".md5" --body "parity_"$VER"_"$IDENT"_"$ARC"."$EXT".md5"
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$BUILD_PLATFORM/"parity_"$VER"_"$IDENT"_"$ARC"."$EXT".sha256" --body "parity_"$VER"_"$IDENT"_"$ARC"."$EXT".sha256"
}
make_archive () {
echo "add artifacts to archive"
rm -rf parity.zip
zip -r parity.zip target/$PLATFORM/release/parity$S3WIN target/$PLATFORM/release/parity-evm$S3WIN target/$PLATFORM/release/ethstore$S3WIN target/$PLATFORM/release/ethkey$S3WIN parity$S3WIN.md5 parity-evm$S3WIN.md5 ethstore$S3WIN.md5 ethkey$S3WIN.md5
zip -r parity.zip target/$PLATFORM/release/parity$S3WIN target/$PLATFORM/release/parity-evm$S3WIN target/$PLATFORM/release/ethstore$S3WIN target/$PLATFORM/release/ethkey$S3WIN parity$S3WIN.md5 parity-evm$S3WIN.md5 ethstore$S3WIN.md5 ethkey$S3WIN.md5 parity$S3WIN.sha256 parity-evm$S3WIN.sha256 ethstore$S3WIN.sha256 ethkey$S3WIN.sha256
}
push_release () {
updater_push_release () {
echo "push release"
curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1338/push-build/$CI_BUILD_REF_NAME/$PLATFORM
DATA="commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity$S3WIN&secret=$RELEASES_SECRET"
# Mainnet
source scripts/safe_curl.sh $DATA "http://update.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$BUILD_PLATFORM"
# Kovan
source scripts/safe_curl.sh $DATA "http://update.parity.io:1338/push-build/$CI_BUILD_REF_NAME/$BUILD_PLATFORM"
}
case $BUILD_PLATFORM in
x86_64-unknown-linux-gnu)
#set strip bin
@@ -186,11 +220,12 @@ case $BUILD_PLATFORM in
#package extention
EXT="deb"
build
strip_md5
strip_binaries
calculate_checksums
make_deb
make_archive
push_binaries
push_release
updater_push_release
;;
x86_64-unknown-debian-gnu)
STRIP_BIN="strip"
@@ -198,95 +233,118 @@ case $BUILD_PLATFORM in
LIBSSL="libssl1.1 (>=1.1.0)"
echo "Use libssl1.1 (>=1.1.0) for Debian builds"
build
strip_md5
strip_binaries
calculate_checksums
make_deb
make_archive
push_binaries
push_release
;;
x86_64-unknown-centos-gnu)
STRIP_BIN="strip"
EXT="rpm"
build
strip_md5
strip_binaries
calculate_checksums
make_rpm
make_archive
push_binaries
push_release
;;
i686-unknown-linux-gnu)
STRIP_BIN="strip"
EXT="deb"
set_env
build
strip_md5
strip_binaries
calculate_checksums
make_deb
make_archive
push_binaries
push_release
;;
armv7-unknown-linux-gnueabihf)
STRIP_BIN="arm-linux-gnueabihf-strip"
EXT="deb"
set_env
build
strip_md5
strip_binaries
calculate_checksums
make_deb
make_archive
push_binaries
push_release
;;
arm-unknown-linux-gnueabihf)
STRIP_BIN="arm-linux-gnueabihf-strip"
EXT="deb"
set_env
build
strip_md5
strip_binaries
calculate_checksums
make_deb
make_archive
push_binaries
push_release
;;
aarch64-unknown-linux-gnu)
STRIP_BIN="aarch64-linux-gnu-strip"
EXT="deb"
set_env
build
strip_md5
strip_binaries
calculate_checksums
make_deb
make_archive
push_binaries
push_release
;;
x86_64-apple-darwin)
STRIP_BIN="strip"
PLATFORM="x86_64-apple-darwin"
EXT="pkg"
build
strip_md5
strip_binaries
calculate_checksums
make_pkg
make_archive
push_binaries
push_release
updater_push_release
;;
x86_64-unknown-snap-gnu)
cd snap
ARC="amd64"
EXT="snap"
rm -rf *snap
sed -i 's/master/'"$VER"'/g' snapcraft.yaml
snapcraft
cp "parity_"$CI_BUILD_REF_NAME"_amd64.snap" "parity_"$VER"_amd64.snap"
md5sum "parity_"$VER"_amd64.snap" > "parity_"$VER"_amd64.snap.md5"
push_binaries
apt install -y expect zip
snapcraft clean
echo "Prepare snapcraft.yaml for build on Gitlab CI in Docker image"
sed -i 's/git/'"$VER"'/g' snap/snapcraft.yaml
if [[ "$CI_BUILD_REF_NAME" = "beta" || "$VER" == *1.9* ]];
then
sed -i -e 's/grade: devel/grade: beta/' snap/snapcraft.yaml;
fi
mv -f snap/snapcraft.yaml snapcraft.yaml
snapcraft -d
snapcraft_login=$(expect -c "
spawn snapcraft login
expect \"Email:\"
send \"$SNAP_EMAIL\n\"
expect \"Password:\"
send \"$SNAP_PASS\n\"
expect \"\$\"
")
echo "$snapcraft_login"
snapcraft push "parity_"$VER"_amd64.snap"
snapcraft status parity
snapcraft logout
$MD5_BIN "parity_"$VER"_amd64.snap" > "parity_"$VER"_amd64.snap.md5"
$SHA256_BIN "parity_"$VER"_amd64.snap" > "parity_"$VER"_amd64.snap.sha256"
echo "add artifacts to archive"
rm -rf parity.zip
zip -r parity.zip "parity_"$VER"_amd64.snap" "parity_"$VER"_amd64.snap.md5" "parity_"$VER"_amd64.snap.sha256"
;;
x86_64-pc-windows-msvc)
set_env_win
EXT="exe"
S3WIN=".exe"
build
sign_exe
calculate_checksums
make_exe
make_archive
push_binaries
push_release
updater_push_release
esac

12
scripts/gitlab-push-release.sh Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/bash
set -e # fail on any error
set -u # treat unset variables as error
DATA="secret=$RELEASES_SECRET"
echo "Pushing release to Mainnet"
./scripts/safe_curl.sh $DATA "http://update.parity.io:1337/push-release/$CI_BUILD_REF_NAME/$CI_BUILD_REF"
echo "Pushing release to Kovan"
./scripts/safe_curl.sh $DATA "http://update.parity.io:1338/push-release/$CI_BUILD_REF_NAME/$CI_BUILD_REF"

View File

@@ -21,11 +21,12 @@ rust_test () {
rustup show
if [[ "${RUST_FILES_MODIFIED}" == "0" ]];
then echo "Skipping Rust tests since no Rust files modified.";
else ./test.sh;
fi
if [[ "$CI_COMMIT_REF_NAME" == "nightly" ]];
then sh scripts/aura-test.sh;
else ./test.sh || exit $?;
fi
# if [[ "$CI_COMMIT_REF_NAME" == "nightly" ]];
# ### @TODO re-enable fail after https://github.com/paritytech/parity-import-tests/issues/3
# then sh scripts/aura-test.sh; # || exit $?;
# fi
}
js_test () {
git submodule update --init --recursive

20
scripts/safe_curl.sh Executable file
View File

@@ -0,0 +1,20 @@
#!/bin/bash
set -eu
DATA=$1
ADDRESS=$2
CODE=$(curl -o out.txt -w '%{http_code}' --data $DATA $ADDRESS)
cat out.txt && rm out.txt
echo "\n"
if [[ $CODE -eq 200 ]]; then
echo 'Pushed to updater service.';
elif [[ $CODE -eq 202 ]]; then
echo 'Updater service ignored request.';
else
echo 'Unable to push info to updater service.';
exit 2
fi

View File

@@ -1,22 +0,0 @@
name: parity
version: master
summary: Fast, light, robust Ethereum implementation
description: |
Parity's goal is to be the fastest, lightest, and most secure Ethereum
client. We are developing Parity using the sophisticated and cutting-edge
Rust programming language. Parity is licensed under the GPLv3, and can be
used for all your Ethereum needs.
grade: devel
confinement: strict
apps:
parity:
command: parity
plugs: [network, network-bind]
parts:
parity:
source: ..
plugin: rust
build-packages: [g++, libudev-dev, libssl-dev, make, pkg-config]

View File

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

View File

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

View File

@@ -35,6 +35,7 @@
use std::collections::{HashMap, HashSet};
use std::mem;
use std::sync::Arc;
use std::time::{Instant, Duration};
use ethcore::encoded;
use light::client::{AsLightClient, LightChainClient};
@@ -58,6 +59,13 @@ mod sync_round;
#[cfg(test)]
mod tests;
// Base number of milliseconds for the header request timeout.
const REQ_TIMEOUT_MILLISECS_BASE: u64 = 7000;
// Additional number of milliseconds for each requested header.
// If we request N headers, then the timeout will be:
// REQ_TIMEOUT_MILLISECS_BASE + N * REQ_TIMEOUT_MILLISECS_PER_HEADER
const REQ_TIMEOUT_MILLISECS_PER_HEADER: u64 = 10;
/// Peer chain info.
#[derive(Debug, Clone, PartialEq, Eq)]
struct ChainInfo {
@@ -225,12 +233,18 @@ pub struct LightSync<L: AsLightClient> {
start_block_number: u64,
best_seen: Mutex<Option<ChainInfo>>, // best seen block on the network.
peers: RwLock<HashMap<PeerId, Mutex<Peer>>>, // peers which are relevant to synchronization.
pending_reqs: Mutex<HashSet<ReqId>>, // requests from this handler.
pending_reqs: Mutex<HashMap<ReqId, PendingReq>>, // requests from this handler
client: Arc<L>,
rng: Mutex<OsRng>,
state: Mutex<SyncState>,
}
#[derive(Debug, Clone)]
struct PendingReq {
started: Instant,
timeout: Duration,
}
impl<L: AsLightClient + Send + Sync> Handler for LightSync<L> {
fn on_connect(
&self,
@@ -353,7 +367,7 @@ impl<L: AsLightClient + Send + Sync> Handler for LightSync<L> {
return
}
if !self.pending_reqs.lock().remove(&req_id) {
if self.pending_reqs.lock().remove(&req_id).is_none() {
return
}
@@ -412,7 +426,7 @@ impl<L: AsLightClient> LightSync<L> {
*state = SyncState::AncestorSearch(AncestorSearch::begin(chain_info.best_block_number));
}
// handles request dispatch, block import, and state machine transitions.
// handles request dispatch, block import, state machine transitions, and timeouts.
fn maintain_sync(&self, ctx: &BasicContext) {
const DRAIN_AMOUNT: usize = 128;
@@ -502,6 +516,32 @@ impl<L: AsLightClient> LightSync<L> {
}
}
// handle requests timeouts
{
let mut pending_reqs = self.pending_reqs.lock();
let mut unfulfilled = Vec::new();
for (req_id, info) in pending_reqs.iter() {
if info.started.elapsed() >= info.timeout {
debug!(target: "sync", "{} timed out", req_id);
unfulfilled.push(req_id.clone());
}
}
if !unfulfilled.is_empty() {
for unfulfilled in unfulfilled.iter() {
pending_reqs.remove(unfulfilled);
}
drop(pending_reqs);
*state = match mem::replace(&mut *state, SyncState::Idle) {
SyncState::Idle => SyncState::Idle,
SyncState::AncestorSearch(search) =>
SyncState::AncestorSearch(search.requests_abandoned(&unfulfilled)),
SyncState::Rounds(round) => SyncState::Rounds(round.requests_abandoned(&unfulfilled)),
};
}
}
// allow dispatching of requests.
{
let peers = self.peers.read();
@@ -535,7 +575,12 @@ impl<L: AsLightClient> LightSync<L> {
if requested_from.contains(peer) { continue }
match ctx.request_from(*peer, request.clone()) {
Ok(id) => {
self.pending_reqs.lock().insert(id.clone());
let timeout_ms = REQ_TIMEOUT_MILLISECS_BASE +
req.max * REQ_TIMEOUT_MILLISECS_PER_HEADER;
self.pending_reqs.lock().insert(id.clone(), PendingReq {
started: Instant::now(),
timeout: Duration::from_millis(timeout_ms),
});
requested_from.insert(peer.clone());
return Some(id)
@@ -571,7 +616,7 @@ impl<L: AsLightClient> LightSync<L> {
start_block_number: client.as_light_client().chain_info().best_block_number,
best_seen: Mutex::new(None),
peers: RwLock::new(HashMap::new()),
pending_reqs: Mutex::new(HashSet::new()),
pending_reqs: Mutex::new(HashMap::new()),
client: client,
rng: Mutex::new(OsRng::new()?),
state: Mutex::new(SyncState::Idle),

View File

@@ -179,7 +179,7 @@ impl Fetcher {
};
trace!(target: "sync", "Received response for subchain ({} -> {})",
request.subchain_parent.0 + 1, request.subchain_end.0);
request.subchain_parent.0, request.subchain_end.0);
let headers = ctx.data();
@@ -241,6 +241,8 @@ impl Fetcher {
}
fn requests_abandoned(mut self, abandoned: &[ReqId]) -> SyncRound {
trace!(target: "sync", "Abandonned requests {:?}", abandoned);
for abandoned in abandoned {
match self.pending.remove(abandoned) {
None => {},
@@ -258,12 +260,14 @@ impl Fetcher {
while let Some(pending_req) = self.requests.pop() {
match dispatcher(pending_req.headers_request.clone()) {
Some(req_id) => {
trace!(target: "sync", "Assigned request for subchain ({} -> {})",
pending_req.subchain_parent.0 + 1, pending_req.subchain_end.0);
trace!(target: "sync", "Assigned request {} for subchain ({} -> {})",
req_id, pending_req.subchain_parent.0, pending_req.subchain_end.0);
self.pending.insert(req_id, pending_req);
}
None => {
trace!(target: "sync", "Failed to assign request for subchain ({} -> {})",
pending_req.subchain_parent.0, pending_req.subchain_end.0);
self.requests.push(pending_req);
break;
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,10 +1,26 @@
# NOTE This file is used by the auto-updater service.
# Make sure to update the service if it's moved or the structure is changed.
[package]
name = "parity-version"
# NOTE: this value is used for Parity version string.
version = "1.9.1"
version = "1.9.3"
authors = ["Parity Technologies <admin@parity.io>"]
build = "build.rs"
[package.metadata]
# This versions track. Should be changed to `stable` or `beta` when on respective branches.
# Used by auto-updater and for Parity version string.
track = "beta"
# Indicates a critical release in this track (i.e. consensus issue)
critical = false
# Latest supported fork blocks for various networks. Used ONLY by auto-updater.
[package.metadata.forks]
foundation = 4370000
ropsten = 10
kovan = 5067000
[dependencies]
ethcore-bytes = { path = "../bytes" }
rlp = { path = "../rlp" }
@@ -13,6 +29,7 @@ target_info = "0.1"
[build-dependencies]
vergen = "0.1"
rustc_version = "0.1.0"
toml = "0.4"
[features]
final = []