Compare commits
14 Commits
v1.10.3-ci
...
v1.10.9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23a9eefd64 | ||
|
|
bd20c45898 | ||
|
|
6438fe9431 | ||
|
|
ba79cad670 | ||
|
|
718b398a17 | ||
|
|
bc0d134bb4 | ||
|
|
f468d705ad | ||
|
|
c7202a771d | ||
|
|
02ffb9be42 | ||
|
|
39b9f1e252 | ||
|
|
226a1d31b6 | ||
|
|
063b0761f5 | ||
|
|
b9ceda38a6 | ||
|
|
d9f6aba308 |
@@ -184,11 +184,14 @@ docker-build:
|
||||
stage: build
|
||||
only:
|
||||
- tags
|
||||
- master
|
||||
- beta
|
||||
- stable
|
||||
- triggers
|
||||
before_script:
|
||||
- docker info
|
||||
script:
|
||||
- if [ "$CI_BUILD_REF_NAME" == "beta" ]; then DOCKER_TAG="latest"; else DOCKER_TAG=$CI_BUILD_REF_NAME; fi
|
||||
- if [ "$CI_BUILD_REF_NAME" == "master" ]; 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
|
||||
|
||||
123
Cargo.lock
generated
123
Cargo.lock
generated
@@ -17,7 +17,7 @@ version = "1.2.1"
|
||||
source = "git+https://github.com/paritytech/app-dirs-rs#0b37f9481ce29e9d5174ad185bca695b206368eb"
|
||||
dependencies = [
|
||||
"ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"xdg 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -1266,7 +1266,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "jsonrpc-core"
|
||||
version = "8.0.1"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10#b5125be0251dd3b45abe14f4e3bd57bd1f1fd45d"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10#2b8e5d5b42b8631009be29ea28dab98946d9d096"
|
||||
dependencies = [
|
||||
"futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1278,7 +1278,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "jsonrpc-http-server"
|
||||
version = "8.0.0"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10#b5125be0251dd3b45abe14f4e3bd57bd1f1fd45d"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10#2b8e5d5b42b8631009be29ea28dab98946d9d096"
|
||||
dependencies = [
|
||||
"hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10)",
|
||||
@@ -1291,7 +1291,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "jsonrpc-ipc-server"
|
||||
version = "8.0.0"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10#b5125be0251dd3b45abe14f4e3bd57bd1f1fd45d"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10#2b8e5d5b42b8631009be29ea28dab98946d9d096"
|
||||
dependencies = [
|
||||
"jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10)",
|
||||
"jsonrpc-server-utils 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10)",
|
||||
@@ -1303,7 +1303,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "jsonrpc-macros"
|
||||
version = "8.0.0"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10#b5125be0251dd3b45abe14f4e3bd57bd1f1fd45d"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10#2b8e5d5b42b8631009be29ea28dab98946d9d096"
|
||||
dependencies = [
|
||||
"jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10)",
|
||||
"jsonrpc-pubsub 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10)",
|
||||
@@ -1313,7 +1313,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "jsonrpc-pubsub"
|
||||
version = "8.0.0"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10#b5125be0251dd3b45abe14f4e3bd57bd1f1fd45d"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10#2b8e5d5b42b8631009be29ea28dab98946d9d096"
|
||||
dependencies = [
|
||||
"jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1323,7 +1323,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "jsonrpc-server-utils"
|
||||
version = "8.0.0"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10#b5125be0251dd3b45abe14f4e3bd57bd1f1fd45d"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10#2b8e5d5b42b8631009be29ea28dab98946d9d096"
|
||||
dependencies = [
|
||||
"bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"globset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1336,7 +1336,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "jsonrpc-tcp-server"
|
||||
version = "8.0.0"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10#b5125be0251dd3b45abe14f4e3bd57bd1f1fd45d"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10#2b8e5d5b42b8631009be29ea28dab98946d9d096"
|
||||
dependencies = [
|
||||
"jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10)",
|
||||
"jsonrpc-server-utils 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10)",
|
||||
@@ -1348,7 +1348,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "jsonrpc-ws-server"
|
||||
version = "8.0.0"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10#b5125be0251dd3b45abe14f4e3bd57bd1f1fd45d"
|
||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10#2b8e5d5b42b8631009be29ea28dab98946d9d096"
|
||||
dependencies = [
|
||||
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.10)",
|
||||
@@ -1620,14 +1620,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mio-named-pipes"
|
||||
version = "0.1.4"
|
||||
source = "git+https://github.com/alexcrichton/mio-named-pipes#9c1bbb985b74374d3b7eda76937279f8e977ef81"
|
||||
version = "0.1.5"
|
||||
source = "git+https://github.com/alexcrichton/mio-named-pipes#6ad80e67fe7993423b281bc13d307785ade05d37"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1650,6 +1649,15 @@ dependencies = [
|
||||
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"socket2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "msdos_time"
|
||||
version = "0.1.5"
|
||||
@@ -1677,6 +1685,11 @@ dependencies = [
|
||||
"tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nan-preserving-float"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "net2"
|
||||
version = "0.2.31"
|
||||
@@ -1862,7 +1875,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "parity"
|
||||
version = "1.10.3"
|
||||
version = "1.10.9"
|
||||
dependencies = [
|
||||
"ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1910,7 +1923,7 @@ dependencies = [
|
||||
"parity-rpc 1.9.0",
|
||||
"parity-rpc-client 1.4.0",
|
||||
"parity-updater 1.9.0",
|
||||
"parity-version 1.10.3",
|
||||
"parity-version 1.10.9",
|
||||
"parity-whisper 0.1.0",
|
||||
"parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"path 0.1.0",
|
||||
@@ -1959,7 +1972,7 @@ dependencies = [
|
||||
"parity-reactor 0.1.0",
|
||||
"parity-ui 1.9.0",
|
||||
"parity-ui-deprecation 1.10.0",
|
||||
"parity-version 1.10.3",
|
||||
"parity-version 1.10.9",
|
||||
"parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1970,20 +1983,6 @@ dependencies = [
|
||||
"zip 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parity-dapps-glue"
|
||||
version = "1.9.1"
|
||||
dependencies = [
|
||||
"aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mime_guess 2.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quasi_macros 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parity-dapps-glue"
|
||||
version = "1.9.1"
|
||||
@@ -2110,7 +2109,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.10.3",
|
||||
"parity-version 1.10.9",
|
||||
"parking_lot 0.5.4 (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.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2150,12 +2149,12 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "parity-tokio-ipc"
|
||||
version = "0.1.5"
|
||||
source = "git+https://github.com/nikvolf/parity-tokio-ipc#d6c5b3cfcc913a1b9cf0f0562a10b083ceb9fb7c"
|
||||
source = "git+https://github.com/nikvolf/parity-tokio-ipc#2af3e5b6b746552d8181069a2c6be068377df1de"
|
||||
dependencies = [
|
||||
"bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)",
|
||||
"mio-named-pipes 0.1.5 (git+https://github.com/alexcrichton/mio-named-pipes)",
|
||||
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2227,7 +2226,7 @@ dependencies = [
|
||||
"ethsync 1.9.0",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-hash-fetch 1.9.0",
|
||||
"parity-version 1.10.3",
|
||||
"parity-version 1.10.9",
|
||||
"parking_lot 0.5.4 (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)",
|
||||
@@ -2236,7 +2235,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "parity-version"
|
||||
version = "1.10.3"
|
||||
version = "1.10.9"
|
||||
dependencies = [
|
||||
"ethcore-bytes 0.1.0",
|
||||
"rlp 0.2.1",
|
||||
@@ -2485,7 +2484,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pwasm-utils"
|
||||
version = "0.1.3"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2517,14 +2516,6 @@ dependencies = [
|
||||
"syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quasi_macros"
|
||||
version = "0.32.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "1.2.1"
|
||||
@@ -2584,7 +2575,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.31"
|
||||
version = "0.1.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -2847,7 +2838,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "shell32-sys"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2919,6 +2910,17 @@ dependencies = [
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spmc"
|
||||
version = "0.2.2"
|
||||
@@ -3083,7 +3085,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -3127,7 +3129,7 @@ source = "git+https://github.com/nikvolf/tokio-named-pipes#0b9b728eaeb0a6673c287
|
||||
dependencies = [
|
||||
"bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)",
|
||||
"mio-named-pipes 0.1.5 (git+https://github.com/alexcrichton/mio-named-pipes)",
|
||||
"tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -3433,18 +3435,19 @@ dependencies = [
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-wasm 0.27.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pwasm-utils 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pwasm-utils 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vm 0.1.0",
|
||||
"wasmi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasmi 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmi"
|
||||
version = "0.1.3"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nan-preserving-float 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-wasm 0.27.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -3667,12 +3670,14 @@ dependencies = [
|
||||
"checksum mime_guess 2.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "27a5e6679a0614e25adc14c6434ba84e41632b765a6d9cb2031a0cca682699ae"
|
||||
"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
|
||||
"checksum mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "6d771e3ef92d58a8da8df7d6976bfca9371ed1de6619d9d5a5ce5b1f29b85bfe"
|
||||
"checksum mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)" = "<none>"
|
||||
"checksum mio-named-pipes 0.1.5 (git+https://github.com/alexcrichton/mio-named-pipes)" = "<none>"
|
||||
"checksum mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1731a873077147b626d89cc6c2a0db6288d607496c5d10c0cfcf3adc697ec673"
|
||||
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||
"checksum miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9224c91f82b3c47cf53dcf78dfaa20d6888fbcc5d272d5f2fcdf8a697f3c987d"
|
||||
"checksum msdos_time 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "65ba9d75bcea84e07812618fedf284a64776c2f2ea0cad6bca7f69739695a958"
|
||||
"checksum multibase 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b9c35dac080fd6e16a99924c8dfdef0af89d797dd851adab25feaffacf7850d6"
|
||||
"checksum multihash 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d49add5f49eb08bfc4d01ff286b84a48f53d45314f165c2d6efe477222d24f3"
|
||||
"checksum nan-preserving-float 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34d4f00fcc2f4c9efa8cc971db0da9e28290e28e97af47585e48691ef10ff31f"
|
||||
"checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09"
|
||||
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
|
||||
"checksum ntp 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "143149743832c6543b60a8ef2a26cd9122dfecec2b767158e852a7beecf6d7a0"
|
||||
@@ -3713,10 +3718,9 @@ dependencies = [
|
||||
"checksum primal-sieve 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c0911abe7b63ddec27527ba7579c3017f645eb992be6ddbfad605e34aca01876"
|
||||
"checksum protobuf 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "568a15e4d572d9a5e63ae3a55f84328c984842887db179b40b4cc6a608bac6a4"
|
||||
"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07"
|
||||
"checksum pwasm-utils 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "54d440c3b56eee028aa5d4f18cbed8c6e0c9ae23563b93f344beb7e73854ea02"
|
||||
"checksum pwasm-utils 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d51e9954a77aab7b4b606dc315a49cbed187924f163b6750cdf6d5677dbf0839"
|
||||
"checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3"
|
||||
"checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4"
|
||||
"checksum quasi_macros 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29cec87bc2816766d7e4168302d505dd06b0a825aed41b00633d296e922e02dd"
|
||||
"checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4"
|
||||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||
"checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1"
|
||||
@@ -3724,7 +3728,7 @@ dependencies = [
|
||||
"checksum rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b614fe08b6665cb9a231d07ac1364b0ef3cb3698f1239ee0c4c3a88a524f54c8"
|
||||
"checksum rayon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed02d09394c94ffbdfdc755ad62a132e94c3224a8354e78a1200ced34df12edf"
|
||||
"checksum rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e64b609139d83da75902f88fd6c01820046840a18471e4dfcd5ac7c0f46bea53"
|
||||
"checksum redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509"
|
||||
"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
|
||||
"checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa"
|
||||
"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db"
|
||||
"checksum relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1576e382688d7e9deecea24417e350d3062d97e32e45d70b1cde65994ff1489a"
|
||||
@@ -3752,7 +3756,7 @@ dependencies = [
|
||||
"checksum serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142"
|
||||
"checksum serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9db7266c7d63a4c4b7fe8719656ccdd51acf1bed6124b174f933b009fb10bcb"
|
||||
"checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c"
|
||||
"checksum shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72f20b8f3c060374edb8046591ba28f62448c369ccbdc7b02075103fb3a9e38d"
|
||||
"checksum shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ee04b46101f57121c9da2b151988283b6beb79b34f5bb29a58ee48cb695122c"
|
||||
"checksum siphasher 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "833011ca526bd88f16778d32c699d325a9ad302fa06381cd66f7be63351d3f6d"
|
||||
"checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
|
||||
"checksum skeptic 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24ebf8a06f5f8bae61ae5bbc7af7aac4ef6907ae975130faba1199e5fe82256a"
|
||||
@@ -3763,6 +3767,7 @@ dependencies = [
|
||||
"checksum smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fcd03faf178110ab0334d74ca9631d77f94c8c11cc77fcb59538abf0025695d"
|
||||
"checksum snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "<none>"
|
||||
"checksum snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "<none>"
|
||||
"checksum socket2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "06dc9f86ee48652b7c80f3d254e3b9accb67a928c562c64d10d7b016d3d98dab"
|
||||
"checksum spmc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cd1f11d1fb5fd41834e55ce0b85a186efbf2f2afd9fdb09e2c8d72f9bff1ad1a"
|
||||
"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
|
||||
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
|
||||
@@ -3814,7 +3819,7 @@ dependencies = [
|
||||
"checksum vergen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c3365f36c57e5df714a34be40902b27a992eeddb9996eca52d0584611cf885d"
|
||||
"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 wasmi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d19da510b59247935ad5f598357b3cc739912666d75d3d28318026478d95bbdb"
|
||||
"checksum wasmi 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46df76793c28cd8f590d5667f540a81c1c245440a17b03560e381226e27cf348"
|
||||
"checksum webpki 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e1622384bcb5458c6a3e3fa572f53ea8fef1cc85e535a2983dea87e9154fac2"
|
||||
"checksum webpki-roots 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "155d4060e5befdf3a6076bd28c22513473d9900b763c9e4521acc6f78a75415c"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
description = "Parity Ethereum client"
|
||||
name = "parity"
|
||||
# NOTE Make sure to update util/version/Cargo.toml as well
|
||||
version = "1.10.3"
|
||||
version = "1.10.9"
|
||||
license = "GPL-3.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
@@ -121,7 +121,6 @@ panic = "abort"
|
||||
[workspace]
|
||||
members = [
|
||||
"chainspec",
|
||||
"dapps/js-glue",
|
||||
"ethcore/wasm/run",
|
||||
"ethcore/types",
|
||||
"ethkey/cli",
|
||||
|
||||
@@ -30,7 +30,7 @@ RUN apt-get update && \
|
||||
# evmjit dependencies
|
||||
zlib1g-dev \
|
||||
libedit-dev \
|
||||
libudev-dev &&\
|
||||
libudev-dev &&\
|
||||
# cmake and llvm ppa's. then update ppa's
|
||||
add-apt-repository -y "ppa:george-edison55/cmake-3.x" && \
|
||||
add-apt-repository "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main" && \
|
||||
|
||||
@@ -54,6 +54,7 @@ pub trait Provider: Send + Sync {
|
||||
/// results within must adhere to the `skip` and `reverse` parameters.
|
||||
fn block_headers(&self, req: request::CompleteHeadersRequest) -> Option<request::HeadersResponse> {
|
||||
use request::HashOrNumber;
|
||||
const MAX_HEADERS_TO_SEND: u64 = 512;
|
||||
|
||||
if req.max == 0 { return None }
|
||||
|
||||
@@ -82,10 +83,12 @@ pub trait Provider: Send + Sync {
|
||||
}
|
||||
};
|
||||
|
||||
let headers: Vec<_> = (0u64..req.max as u64)
|
||||
.map(|x: u64| x.saturating_mul(req.skip + 1))
|
||||
let max = ::std::cmp::min(MAX_HEADERS_TO_SEND, req.max);
|
||||
|
||||
let headers: Vec<_> = (0u64..max)
|
||||
.map(|x: u64| x.saturating_mul(req.skip.saturating_add(1)))
|
||||
.take_while(|x| if req.reverse { x < &start_num } else { best_num.saturating_sub(start_num) >= *x })
|
||||
.map(|x| if req.reverse { start_num - x } else { start_num + x })
|
||||
.map(|x| if req.reverse { start_num.saturating_sub(x) } else { start_num.saturating_add(x) })
|
||||
.map(|x| self.block_header(BlockId::Number(x)))
|
||||
.take_while(|x| x.is_some())
|
||||
.flat_map(|x| x)
|
||||
|
||||
@@ -57,7 +57,8 @@
|
||||
"enode://814920f1ec9510aa9ea1c8f79d8b6e6a462045f09caa2ae4055b0f34f7416fca6facd3dd45f1cf1673c0209e0503f02776b8ff94020e98b6679a0dc561b4eba0@104.154.136.117:30303",
|
||||
"enode://72e445f4e89c0f476d404bc40478b0df83a5b500d2d2e850e08eb1af0cd464ab86db6160d0fde64bd77d5f0d33507ae19035671b3c74fec126d6e28787669740@104.198.71.200:30303",
|
||||
"enode://39abab9d2a41f53298c0c9dc6bbca57b0840c3ba9dccf42aa27316addc1b7e56ade32a0a9f7f52d6c5db4fe74d8824bcedfeaecf1a4e533cacb71cf8100a9442@144.76.238.49:30303",
|
||||
"enode://f50e675a34f471af2438b921914b5f06499c7438f3146f6b8936f1faeb50b8a91d0d0c24fb05a66f05865cd58c24da3e664d0def806172ddd0d4c5bdbf37747e@144.76.238.49:30306"
|
||||
"enode://f50e675a34f471af2438b921914b5f06499c7438f3146f6b8936f1faeb50b8a91d0d0c24fb05a66f05865cd58c24da3e664d0def806172ddd0d4c5bdbf37747e@144.76.238.49:30306",
|
||||
"enode://83b33409349ffa25e150555f7b4f8deebc68f3d34d782129dc3c8ba07b880c209310a4191e1725f2f6bef59bce9452d821111eaa786deab08a7e6551fca41f4f@159.89.223.6:30303"
|
||||
],
|
||||
"accounts": {
|
||||
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
"eip150Transition": "0x0",
|
||||
"eip160Transition": "0x0",
|
||||
"ecip1017EraRounds": 10000000,
|
||||
|
||||
"eip161abcTransition": "0x7fffffffffffffff",
|
||||
"eip161dTransition": "0x7fffffffffffffff"
|
||||
"eip161dTransition": "0x7fffffffffffffff",
|
||||
"eip100bTransition": 2000000
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -29,7 +29,12 @@
|
||||
"chainID": "0x40",
|
||||
"eip155Transition": "0x0",
|
||||
"eip98Transition": "0x7fffffffffffff",
|
||||
"eip86Transition": "0x7fffffffffffff"
|
||||
"eip86Transition": "0x7fffffffffffff",
|
||||
"wasmActivationTransition": 2000000,
|
||||
"eip140Transition": 2000000,
|
||||
"eip211Transition": 2000000,
|
||||
"eip214Transition": 2000000,
|
||||
"eip658Transition": 2000000
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
@@ -67,6 +72,10 @@
|
||||
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||
"0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||
"0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }
|
||||
"0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
|
||||
"0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": 2000000, "pricing": { "modexp": { "divisor": 20 } } } },
|
||||
"0000000000000000000000000000000000000006": { "builtin": { "name": "alt_bn128_add", "activate_at": 2000000, "pricing": { "linear": { "base": 500, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000007": { "builtin": { "name": "alt_bn128_mul", "activate_at": 2000000, "pricing": { "linear": { "base": 40000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000008": { "builtin": { "name": "alt_bn128_pairing", "activate_at": 2000000, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,16 +174,13 @@
|
||||
"stateRoot": "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544"
|
||||
},
|
||||
"nodes": [
|
||||
"enode://81863f47e9bd652585d3f78b4b2ee07b93dad603fd9bc3c293e1244250725998adc88da0cef48f1de89b15ab92b15db8f43dc2b6fb8fbd86a6f217a1dd886701@193.70.55.37:30303",
|
||||
"enode://4afb3a9137a88267c02651052cf6fb217931b8c78ee058bb86643542a4e2e0a8d24d47d871654e1b78a276c363f3c1bc89254a973b00adc359c9e9a48f140686@144.217.139.5:30303",
|
||||
"enode://c16d390b32e6eb1c312849fe12601412313165df1a705757d671296f1ac8783c5cff09eab0118ac1f981d7148c85072f0f26407e5c68598f3ad49209fade404d@139.99.51.203:30303",
|
||||
"enode://4faf867a2e5e740f9b874e7c7355afee58a2d1ace79f7b692f1d553a1134eddbeb5f9210dd14dc1b774a46fd5f063a8bc1fa90579e13d9d18d1f59bac4a4b16b@139.99.160.213:30303",
|
||||
"enode://6a868ced2dec399c53f730261173638a93a40214cf299ccf4d42a76e3fa54701db410669e8006347a4b3a74fa090bb35af0320e4bc8d04cf5b7f582b1db285f5@163.172.131.191:30303",
|
||||
"enode://66a483383882a518fcc59db6c017f9cd13c71261f13c8d7e67ed43adbbc82a932d88d2291f59be577e9425181fc08828dc916fdd053af935a9491edf9d6006ba@212.47.247.103:30303",
|
||||
"enode://cd6611461840543d5b9c56fbf088736154c699c43973b3a1a32390cf27106f87e58a818a606ccb05f3866de95a4fe860786fea71bf891ea95f234480d3022aa3@163.172.157.114:30303",
|
||||
"enode://78b094cb27ceeecbe311bc278f4fde8b9a265db42d268c88484c94d7a2d19b82a1bd22dfd6c2bd4d90f9b05e6d42255e6eb85de15f73848ff82ed0be9cdf5202@52.233.198.218:30303",
|
||||
"enode://00526537cb7e1aa6cf49714f0635fd0f608904d8d0693b949eea2dcdfdb0abbe4c794003a5fe57aa662d0a9215e8dfa4d2deb6ef0101c5e185e2617721813d43@40.65.122.44:30303",
|
||||
"enode://4a456b4b6e6ee1f51389763e51b80fe04782c762445d96c32a96ebd34bd9178c1894924d5101123eacfd4f0fc4da25b5e1ee7f18832ac0bf4c6d6ac81442d698@40.71.6.49:3030",
|
||||
"enode://68f85e7403976aa92318eff804cbe9bc988e0f5230d9d07ae4def030cbae16603262638e272d19875b7e5c54e296ba88ab6ec6e98face9e2537346c4dce78882@52.243.47.211:30303",
|
||||
"enode://dc72806c3aa8fda207c8c018aba8d6cf143728b3628b6ded8d5e8cdeb8aa05cbd53f710ecd014c9a8f0d1e98f2874bff8afb15a229202f510a9c0258d1f6d109@159.203.210.80:30303",
|
||||
"enode://5a62f19d35c0da8b576c9414568c728d4744e6e9d436c0f9db27456400011414f515871f13a6b8e0468534b5116cfe765d7630f680f1707a38467940a9f62511@45.55.33.62:30303",
|
||||
"enode://605e04a43b1156966b3a3b66b980c87b7f18522f7f712035f84576016be909a2798a438b2b17b1a8c58db314d88539a77419ca4be36148c086900fba487c9d39@188.166.255.12:30303",
|
||||
"enode://1d1f7bcb159d308eb2f3d5e32dc5f8786d714ec696bb2f7e3d982f9bcd04c938c139432f13aadcaf5128304a8005e8606aebf5eebd9ec192a1471c13b5e31d49@138.201.223.35:30303",
|
||||
"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303",
|
||||
"enode://3f1d12044546b76342d59d4a05532c14b85aa669704bfe1f864fe079415aa2c02d743e03218e57a33fb94523adb54032871a6c51b2cc5514cb7c7e35b3ed0a99@13.93.211.84:30303",
|
||||
@@ -195,7 +192,6 @@
|
||||
"enode://1c7a64d76c0334b0418c004af2f67c50e36a3be60b5e4790bdac0439d21603469a85fad36f2473c9a80eb043ae60936df905fa28f1ff614c3e5dc34f15dcd2dc@40.118.3.223:30308",
|
||||
"enode://85c85d7143ae8bb96924f2b54f1b3e70d8c4d367af305325d30a61385a432f247d2c75c45c6b4a60335060d072d7f5b35dd1d4c45f76941f62a4f83b6e75daaf@40.118.3.223:30309",
|
||||
"enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303",
|
||||
"enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303",
|
||||
"enode://4cd540b2c3292e17cff39922e864094bf8b0741fcc8c5dcea14957e389d7944c70278d872902e3d0345927f621547efa659013c400865485ab4bfa0c6596936f@138.201.144.135:30303",
|
||||
"enode://01f76fa0561eca2b9a7e224378dd854278735f1449793c46ad0c4e79e8775d080c21dcc455be391e90a98153c3b05dcc8935c8440de7b56fe6d67251e33f4e3c@51.15.42.252:30303",
|
||||
"enode://2c9059f05c352b29d559192fe6bca272d965c9f2290632a2cfda7f83da7d2634f3ec45ae3a72c54dd4204926fb8082dcf9686e0d7504257541c86fc8569bcf4b@163.172.171.38:30303",
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID" : "0x3",
|
||||
"forkBlock": 641350,
|
||||
"forkCanonHash": "0x8033403e9fe5811a7b6d6b469905915de1c59207ce2172cbcf5d6ff14fa6a2eb",
|
||||
"forkBlock": 3383558,
|
||||
"forkCanonHash": "0x6b4b80d65951375a70bc1ecf9a270d152dd355454d57869abbae2e42c213e0f3",
|
||||
"maxCodeSize": 24576,
|
||||
"maxCodeSizeTransition": 10,
|
||||
"eip155Transition": 10,
|
||||
|
||||
54
ethcore/res/ethereum/tobalaba.json
Normal file
54
ethcore/res/ethereum/tobalaba.json
Normal file
File diff suppressed because one or more lines are too long
@@ -57,6 +57,12 @@ pub trait BlockProvider {
|
||||
/// (though not necessarily a part of the canon chain).
|
||||
fn is_known(&self, hash: &H256) -> bool;
|
||||
|
||||
/// Returns true if the given block is known and in the canon chain.
|
||||
fn is_canon(&self, hash: &H256) -> bool {
|
||||
let is_canon = || Some(hash == &self.block_hash(self.block_number(hash)?)?);
|
||||
is_canon().unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Get the first block of the best part of the chain.
|
||||
/// Return `None` if there is no gap and the first block is the genesis.
|
||||
/// Any queries of blocks which precede this one are not guaranteed to
|
||||
@@ -153,7 +159,7 @@ pub trait BlockProvider {
|
||||
fn blocks_with_bloom(&self, bloom: &Bloom, from_block: BlockNumber, to_block: BlockNumber) -> Vec<BlockNumber>;
|
||||
|
||||
/// Returns logs matching given filter.
|
||||
fn logs<F>(&self, blocks: Vec<BlockNumber>, matches: F, limit: Option<usize>) -> Vec<LocalizedLogEntry>
|
||||
fn logs<F>(&self, blocks: Vec<H256>, matches: F, limit: Option<usize>) -> Vec<LocalizedLogEntry>
|
||||
where F: Fn(&LogEntry) -> bool + Send + Sync, Self: Sized;
|
||||
}
|
||||
|
||||
@@ -360,16 +366,18 @@ impl BlockProvider for BlockChain {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn logs<F>(&self, mut blocks: Vec<BlockNumber>, matches: F, limit: Option<usize>) -> Vec<LocalizedLogEntry>
|
||||
/// Returns logs matching given filter. The order of logs returned will be the same as the order of the blocks
|
||||
/// provided. And it's the callers responsibility to sort blocks provided in advance.
|
||||
fn logs<F>(&self, mut blocks: Vec<H256>, matches: F, limit: Option<usize>) -> Vec<LocalizedLogEntry>
|
||||
where F: Fn(&LogEntry) -> bool + Send + Sync, Self: Sized {
|
||||
// sort in reverse order
|
||||
blocks.sort_by(|a, b| b.cmp(a));
|
||||
blocks.reverse();
|
||||
|
||||
let mut logs = blocks
|
||||
.chunks(128)
|
||||
.flat_map(move |blocks_chunk| {
|
||||
blocks_chunk.into_par_iter()
|
||||
.filter_map(|number| self.block_hash(*number).map(|hash| (*number, hash)))
|
||||
.filter_map(|hash| self.block_number(&hash).map(|r| (r, hash)))
|
||||
.filter_map(|(number, hash)| self.block_receipts(&hash).map(|r| (number, hash, r.receipts)))
|
||||
.filter_map(|(number, hash, receipts)| self.block_body(&hash).map(|ref b| (number, hash, receipts, b.transaction_hashes())))
|
||||
.flat_map(|(number, hash, mut receipts, mut hashes)| {
|
||||
@@ -396,7 +404,7 @@ impl BlockProvider for BlockChain {
|
||||
.enumerate()
|
||||
.map(move |(i, log)| LocalizedLogEntry {
|
||||
entry: log,
|
||||
block_hash: hash,
|
||||
block_hash: *hash,
|
||||
block_number: number,
|
||||
transaction_hash: tx_hash,
|
||||
// iterating in reverse order
|
||||
@@ -1417,18 +1425,24 @@ impl BlockChain {
|
||||
|
||||
/// Returns general blockchain information
|
||||
pub fn chain_info(&self) -> BlockChainInfo {
|
||||
// Make sure to call internal methods first to avoid
|
||||
// recursive locking of `best_block`.
|
||||
let first_block_hash = self.first_block();
|
||||
let first_block_number = self.first_block_number().into();
|
||||
let genesis_hash = self.genesis_hash();
|
||||
|
||||
// ensure data consistencly by locking everything first
|
||||
let best_block = self.best_block.read();
|
||||
let best_ancient_block = self.best_ancient_block.read();
|
||||
BlockChainInfo {
|
||||
total_difficulty: best_block.total_difficulty.clone(),
|
||||
pending_total_difficulty: best_block.total_difficulty.clone(),
|
||||
genesis_hash: self.genesis_hash(),
|
||||
genesis_hash,
|
||||
best_block_hash: best_block.hash,
|
||||
best_block_number: best_block.number,
|
||||
best_block_timestamp: best_block.timestamp,
|
||||
first_block_hash: self.first_block(),
|
||||
first_block_number: From::from(self.first_block_number()),
|
||||
first_block_hash,
|
||||
first_block_number,
|
||||
ancient_block_hash: best_ancient_block.as_ref().map(|b| b.hash),
|
||||
ancient_block_number: best_ancient_block.as_ref().map(|b| b.number),
|
||||
}
|
||||
@@ -1957,17 +1971,33 @@ mod tests {
|
||||
value: 103.into(),
|
||||
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
||||
}.sign(&secret(), None);
|
||||
let t4 = Transaction {
|
||||
nonce: 0.into(),
|
||||
gas_price: 0.into(),
|
||||
gas: 100_000.into(),
|
||||
action: Action::Create,
|
||||
value: 104.into(),
|
||||
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
||||
}.sign(&secret(), None);
|
||||
let tx_hash1 = t1.hash();
|
||||
let tx_hash2 = t2.hash();
|
||||
let tx_hash3 = t3.hash();
|
||||
let tx_hash4 = t4.hash();
|
||||
|
||||
let genesis = BlockBuilder::genesis();
|
||||
let b1 = genesis.add_block_with_transactions(vec![t1, t2]);
|
||||
let b2 = b1.add_block_with_transactions(iter::once(t3));
|
||||
let b3 = genesis.add_block_with(|| BlockOptions {
|
||||
transactions: vec![t4.clone()],
|
||||
difficulty: U256::from(9),
|
||||
..Default::default()
|
||||
}); // Branch block
|
||||
let b1_hash = b1.last().hash();
|
||||
let b1_number = b1.last().number();
|
||||
let b2_hash = b2.last().hash();
|
||||
let b2_number = b2.last().number();
|
||||
let b3_hash = b3.last().hash();
|
||||
let b3_number = b3.last().number();
|
||||
|
||||
let db = new_db();
|
||||
let bc = new_chain(&genesis.last().encoded(), db.clone());
|
||||
@@ -1998,10 +2028,21 @@ mod tests {
|
||||
],
|
||||
}
|
||||
]);
|
||||
insert_block(&db, &bc, &b3.last().encoded(), vec![
|
||||
Receipt {
|
||||
outcome: TransactionOutcome::StateRoot(H256::default()),
|
||||
gas_used: 10_000.into(),
|
||||
log_bloom: Default::default(),
|
||||
logs: vec![
|
||||
LogEntry { address: Default::default(), topics: vec![], data: vec![5], },
|
||||
],
|
||||
}
|
||||
]);
|
||||
|
||||
// when
|
||||
let logs1 = bc.logs(vec![1, 2], |_| true, None);
|
||||
let logs2 = bc.logs(vec![1, 2], |_| true, Some(1));
|
||||
let logs1 = bc.logs(vec![b1_hash, b2_hash], |_| true, None);
|
||||
let logs2 = bc.logs(vec![b1_hash, b2_hash], |_| true, Some(1));
|
||||
let logs3 = bc.logs(vec![b3_hash], |_| true, None);
|
||||
|
||||
// then
|
||||
assert_eq!(logs1, vec![
|
||||
@@ -2053,6 +2094,17 @@ mod tests {
|
||||
log_index: 0,
|
||||
}
|
||||
]);
|
||||
assert_eq!(logs3, vec![
|
||||
LocalizedLogEntry {
|
||||
entry: LogEntry { address: Default::default(), topics: vec![], data: vec![5] },
|
||||
block_hash: b3_hash,
|
||||
block_number: b3_number,
|
||||
transaction_hash: tx_hash4,
|
||||
transaction_index: 0,
|
||||
transaction_log_index: 0,
|
||||
log_index: 0,
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::collections::{HashSet, HashMap, BTreeMap, VecDeque};
|
||||
use std::collections::{HashSet, HashMap, BTreeMap, BTreeSet, VecDeque};
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering};
|
||||
@@ -944,7 +944,8 @@ impl Client {
|
||||
match id {
|
||||
BlockId::Pending => self.state_at(BlockId::Latest),
|
||||
id => match self.block_number(id) {
|
||||
None | Some(0) => None,
|
||||
None => None,
|
||||
Some(0) => self.state_at(id),
|
||||
Some(n) => self.state_at(BlockId::Number(n - 1)),
|
||||
}
|
||||
}
|
||||
@@ -1666,23 +1667,83 @@ impl BlockChainClient for Client {
|
||||
}
|
||||
|
||||
fn logs(&self, filter: Filter) -> Vec<LocalizedLogEntry> {
|
||||
let (from, to) = match (self.block_number_ref(&filter.from_block), self.block_number_ref(&filter.to_block)) {
|
||||
(Some(from), Some(to)) => (from, to),
|
||||
_ => return Vec::new(),
|
||||
// Wrap the logic inside a closure so that we can take advantage of question mark syntax.
|
||||
let fetch_logs = || {
|
||||
let chain = self.chain.read();
|
||||
|
||||
// First, check whether `filter.from_block` and `filter.to_block` is on the canon chain. If so, we can use the
|
||||
// optimized version.
|
||||
let is_canon = |id| {
|
||||
match id {
|
||||
&BlockId::Pending => true,
|
||||
// If it is referred by number, then it is always on the canon chain.
|
||||
&BlockId::Earliest | &BlockId::Latest | &BlockId::Number(_) => true,
|
||||
// If it is referred by hash, we see whether a hash -> number -> hash conversion gives us the same
|
||||
// result.
|
||||
&BlockId::Hash(ref hash) => chain.is_canon(hash),
|
||||
}
|
||||
};
|
||||
|
||||
let blocks = if is_canon(&filter.from_block) && is_canon(&filter.to_block) {
|
||||
// If we are on the canon chain, use bloom filter to fetch required hashes.
|
||||
let from = self.block_number_ref(&filter.from_block)?;
|
||||
let to = self.block_number_ref(&filter.to_block)?;
|
||||
|
||||
filter.bloom_possibilities().iter()
|
||||
.map(|bloom| {
|
||||
chain.blocks_with_bloom(bloom, from, to)
|
||||
})
|
||||
.flat_map(|m| m)
|
||||
// remove duplicate elements
|
||||
.collect::<BTreeSet<u64>>()
|
||||
.into_iter()
|
||||
.filter_map(|n| chain.block_hash(n))
|
||||
.collect::<Vec<H256>>()
|
||||
|
||||
} else {
|
||||
// Otherwise, we use a slower version that finds a link between from_block and to_block.
|
||||
let from_hash = Self::block_hash(&chain, &*self.miner, filter.from_block)?;
|
||||
let from_number = chain.block_number(&from_hash)?;
|
||||
let to_hash = Self::block_hash(&chain, &*self.miner, filter.from_block)?;
|
||||
|
||||
let blooms = filter.bloom_possibilities();
|
||||
let bloom_match = |header: &encoded::Header| {
|
||||
blooms.iter().any(|bloom| header.log_bloom().contains_bloom(bloom))
|
||||
};
|
||||
|
||||
let (blocks, last_hash) = {
|
||||
let mut blocks = Vec::new();
|
||||
let mut current_hash = to_hash;
|
||||
|
||||
loop {
|
||||
let header = chain.block_header_data(¤t_hash)?;
|
||||
if bloom_match(&header) {
|
||||
blocks.push(current_hash);
|
||||
}
|
||||
|
||||
// Stop if `from` block is reached.
|
||||
if header.number() <= from_number {
|
||||
break;
|
||||
}
|
||||
current_hash = header.parent_hash();
|
||||
}
|
||||
|
||||
blocks.reverse();
|
||||
(blocks, current_hash)
|
||||
};
|
||||
|
||||
// Check if we've actually reached the expected `from` block.
|
||||
if last_hash != from_hash || blocks.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
blocks
|
||||
};
|
||||
|
||||
Some(self.chain.read().logs(blocks, |entry| filter.matches(entry), filter.limit))
|
||||
};
|
||||
|
||||
let chain = self.chain.read();
|
||||
let blocks = filter.bloom_possibilities().iter()
|
||||
.map(move |bloom| {
|
||||
chain.blocks_with_bloom(bloom, from, to)
|
||||
})
|
||||
.flat_map(|m| m)
|
||||
// remove duplicate elements
|
||||
.collect::<HashSet<u64>>()
|
||||
.into_iter()
|
||||
.collect::<Vec<u64>>();
|
||||
|
||||
self.chain.read().logs(blocks, |entry| filter.matches(entry), filter.limit)
|
||||
fetch_logs().unwrap_or_default()
|
||||
}
|
||||
|
||||
fn filter_traces(&self, filter: TraceFilter) -> Option<Vec<LocalizedTrace>> {
|
||||
|
||||
@@ -16,12 +16,13 @@
|
||||
|
||||
//! A blockchain engine that supports a non-instant BFT proof-of-authority.
|
||||
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
use std::fmt;
|
||||
use std::iter::FromIterator;
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering};
|
||||
use std::sync::{Weak, Arc};
|
||||
use std::time::{UNIX_EPOCH, Duration};
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
use std::iter::FromIterator;
|
||||
|
||||
use account_provider::AccountProvider;
|
||||
use block::*;
|
||||
@@ -374,12 +375,16 @@ impl Decodable for SealedEmptyStep {
|
||||
}
|
||||
}
|
||||
|
||||
struct PermissionedStep {
|
||||
inner: Step,
|
||||
can_propose: AtomicBool,
|
||||
}
|
||||
|
||||
/// Engine using `AuthorityRound` proof-of-authority BFT consensus.
|
||||
pub struct AuthorityRound {
|
||||
transition_service: IoService<()>,
|
||||
step: Arc<Step>,
|
||||
can_propose: AtomicBool,
|
||||
client: RwLock<Option<Weak<EngineClient>>>,
|
||||
step: Arc<PermissionedStep>,
|
||||
client: Arc<RwLock<Option<Weak<EngineClient>>>>,
|
||||
signer: RwLock<EngineSigner>,
|
||||
validators: Box<ValidatorSet>,
|
||||
validate_score_transition: u64,
|
||||
@@ -397,7 +402,7 @@ pub struct AuthorityRound {
|
||||
|
||||
// header-chain validator.
|
||||
struct EpochVerifier {
|
||||
step: Arc<Step>,
|
||||
step: Arc<PermissionedStep>,
|
||||
subchain_validators: SimpleList,
|
||||
empty_steps_transition: u64,
|
||||
}
|
||||
@@ -405,7 +410,7 @@ struct EpochVerifier {
|
||||
impl super::EpochVerifier<EthereumMachine> for EpochVerifier {
|
||||
fn verify_light(&self, header: &Header) -> Result<(), Error> {
|
||||
// Validate the timestamp
|
||||
verify_timestamp(&*self.step, header_step(header, self.empty_steps_transition)?)?;
|
||||
verify_timestamp(&self.step.inner, header_step(header, self.empty_steps_transition)?)?;
|
||||
// always check the seal since it's fast.
|
||||
// nothing heavier to do.
|
||||
verify_external(header, &self.subchain_validators, self.empty_steps_transition)
|
||||
@@ -560,7 +565,6 @@ fn verify_external(header: &Header, validators: &ValidatorSet, empty_steps_trans
|
||||
|
||||
if is_invalid_proposer {
|
||||
trace!(target: "engine", "verify_block_external: bad proposer for step: {}", header_step);
|
||||
validators.report_benign(header.author(), header.number(), header.number());
|
||||
Err(EngineError::NotProposer(Mismatch { expected: correct_proposer, found: header.author().clone() }))?
|
||||
} else {
|
||||
Ok(())
|
||||
@@ -592,6 +596,23 @@ impl AsMillis for Duration {
|
||||
}
|
||||
}
|
||||
|
||||
// A type for storing owned or borrowed data that has a common type.
|
||||
// Useful for returning either a borrow or owned data from a function.
|
||||
enum CowLike<'a, A: 'a + ?Sized, B> {
|
||||
Borrowed(&'a A),
|
||||
Owned(B),
|
||||
}
|
||||
|
||||
impl<'a, A: ?Sized, B> Deref for CowLike<'a, A, B> where B: AsRef<A> {
|
||||
type Target = A;
|
||||
fn deref(&self) -> &A {
|
||||
match self {
|
||||
CowLike::Borrowed(b) => b,
|
||||
CowLike::Owned(o) => o.as_ref(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AuthorityRound {
|
||||
/// Create a new instance of AuthorityRound engine.
|
||||
pub fn new(our_params: AuthorityRoundParams, machine: EthereumMachine) -> Result<Arc<Self>, Error> {
|
||||
@@ -604,13 +625,15 @@ impl AuthorityRound {
|
||||
let engine = Arc::new(
|
||||
AuthorityRound {
|
||||
transition_service: IoService::<()>::start()?,
|
||||
step: Arc::new(Step {
|
||||
inner: AtomicUsize::new(initial_step),
|
||||
calibrate: our_params.start_step.is_none(),
|
||||
duration: our_params.step_duration,
|
||||
step: Arc::new(PermissionedStep {
|
||||
inner: Step {
|
||||
inner: AtomicUsize::new(initial_step),
|
||||
calibrate: our_params.start_step.is_none(),
|
||||
duration: our_params.step_duration,
|
||||
},
|
||||
can_propose: AtomicBool::new(true),
|
||||
}),
|
||||
can_propose: AtomicBool::new(true),
|
||||
client: RwLock::new(None),
|
||||
client: Arc::new(RwLock::new(None)),
|
||||
signer: Default::default(),
|
||||
validators: our_params.validators,
|
||||
validate_score_transition: our_params.validate_score_transition,
|
||||
@@ -628,12 +651,39 @@ impl AuthorityRound {
|
||||
|
||||
// Do not initialize timeouts for tests.
|
||||
if should_timeout {
|
||||
let handler = TransitionHandler { engine: Arc::downgrade(&engine) };
|
||||
let handler = TransitionHandler {
|
||||
step: engine.step.clone(),
|
||||
client: engine.client.clone(),
|
||||
};
|
||||
engine.transition_service.register_handler(Arc::new(handler))?;
|
||||
}
|
||||
Ok(engine)
|
||||
}
|
||||
|
||||
// fetch correct validator set for epoch at header, taking into account
|
||||
// finality of previous transitions.
|
||||
fn epoch_set<'a>(&'a self, header: &Header) -> Result<(CowLike<ValidatorSet, SimpleList>, BlockNumber), Error> {
|
||||
Ok(if self.immediate_transitions {
|
||||
(CowLike::Borrowed(&*self.validators), header.number())
|
||||
} else {
|
||||
let mut epoch_manager = self.epoch_manager.lock();
|
||||
let client = match self.client.read().as_ref().and_then(|weak| weak.upgrade()) {
|
||||
Some(client) => client,
|
||||
None => {
|
||||
debug!(target: "engine", "Unable to verify sig: missing client ref.");
|
||||
return Err(EngineError::RequiresClient.into())
|
||||
}
|
||||
};
|
||||
|
||||
if !epoch_manager.zoom_to(&*client, &self.machine, &*self.validators, header) {
|
||||
debug!(target: "engine", "Unable to zoom to epoch.");
|
||||
return Err(EngineError::RequiresClient.into())
|
||||
}
|
||||
|
||||
(CowLike::Owned(epoch_manager.validators().clone()), epoch_manager.epoch_transition_number)
|
||||
})
|
||||
}
|
||||
|
||||
fn empty_steps(&self, from_step: U256, to_step: U256, parent_hash: H256) -> Vec<EmptyStep> {
|
||||
self.empty_steps.lock().iter().filter(|e| {
|
||||
U256::from(e.step) > from_step &&
|
||||
@@ -654,7 +704,7 @@ impl AuthorityRound {
|
||||
}
|
||||
|
||||
fn generate_empty_step(&self, parent_hash: &H256) {
|
||||
let step = self.step.load();
|
||||
let step = self.step.inner.load();
|
||||
let empty_step_rlp = empty_step_rlp(step, parent_hash);
|
||||
|
||||
if let Ok(signature) = self.sign(keccak(&empty_step_rlp)).map(Into::into) {
|
||||
@@ -679,6 +729,28 @@ impl AuthorityRound {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn report_skipped(&self, header: &Header, current_step: usize, parent_step: usize, validators: &ValidatorSet, set_number: u64) {
|
||||
// we're building on top of the genesis block so don't report any skipped steps
|
||||
if header.number() == 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
if let (true, Some(me)) = (current_step > parent_step + 1, self.signer.read().address()) {
|
||||
debug!(target: "engine", "Author {} built block with step gap. current step: {}, parent step: {}",
|
||||
header.author(), current_step, parent_step);
|
||||
let mut reported = HashSet::new();
|
||||
for step in parent_step + 1..current_step {
|
||||
let skipped_primary = step_proposer(validators, header.parent_hash(), step);
|
||||
// Do not report this signer.
|
||||
if skipped_primary != me {
|
||||
// Stop reporting once validators start repeating.
|
||||
if !reported.insert(skipped_primary) { break; }
|
||||
self.validators.report_benign(&skipped_primary, set_number, header.number());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unix_now() -> Duration {
|
||||
@@ -686,34 +758,37 @@ fn unix_now() -> Duration {
|
||||
}
|
||||
|
||||
struct TransitionHandler {
|
||||
engine: Weak<AuthorityRound>,
|
||||
step: Arc<PermissionedStep>,
|
||||
client: Arc<RwLock<Option<Weak<EngineClient>>>>,
|
||||
}
|
||||
|
||||
const ENGINE_TIMEOUT_TOKEN: TimerToken = 23;
|
||||
|
||||
impl IoHandler<()> for TransitionHandler {
|
||||
fn initialize(&self, io: &IoContext<()>) {
|
||||
if let Some(engine) = self.engine.upgrade() {
|
||||
let remaining = engine.step.duration_remaining();
|
||||
io.register_timer_once(ENGINE_TIMEOUT_TOKEN, remaining.as_millis())
|
||||
.unwrap_or_else(|e| warn!(target: "engine", "Failed to start consensus step timer: {}.", e))
|
||||
}
|
||||
let remaining = self.step.inner.duration_remaining().as_millis();
|
||||
io.register_timer_once(ENGINE_TIMEOUT_TOKEN, remaining)
|
||||
.unwrap_or_else(|e| warn!(target: "engine", "Failed to start consensus step timer: {}.", e))
|
||||
}
|
||||
|
||||
fn timeout(&self, io: &IoContext<()>, timer: TimerToken) {
|
||||
if timer == ENGINE_TIMEOUT_TOKEN {
|
||||
if let Some(engine) = self.engine.upgrade() {
|
||||
// NOTE we might be lagging by couple of steps in case the timeout
|
||||
// has not been called fast enough.
|
||||
// Make sure to advance up to the actual step.
|
||||
while engine.step.duration_remaining().as_millis() == 0 {
|
||||
engine.step();
|
||||
// NOTE we might be lagging by couple of steps in case the timeout
|
||||
// has not been called fast enough.
|
||||
// Make sure to advance up to the actual step.
|
||||
while self.step.inner.duration_remaining().as_millis() == 0 {
|
||||
self.step.inner.increment();
|
||||
self.step.can_propose.store(true, AtomicOrdering::SeqCst);
|
||||
if let Some(ref weak) = *self.client.read() {
|
||||
if let Some(c) = weak.upgrade() {
|
||||
c.update_sealing();
|
||||
}
|
||||
}
|
||||
|
||||
let next_run_at = engine.step.duration_remaining().as_millis() >> 2;
|
||||
io.register_timer_once(ENGINE_TIMEOUT_TOKEN, next_run_at)
|
||||
.unwrap_or_else(|e| warn!(target: "engine", "Failed to restart consensus step timer: {}.", e))
|
||||
}
|
||||
|
||||
let next_run_at = self.step.inner.duration_remaining().as_millis() >> 2;
|
||||
io.register_timer_once(ENGINE_TIMEOUT_TOKEN, next_run_at)
|
||||
.unwrap_or_else(|e| warn!(target: "engine", "Failed to restart consensus step timer: {}.", e))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -730,8 +805,8 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
}
|
||||
|
||||
fn step(&self) {
|
||||
self.step.increment();
|
||||
self.can_propose.store(true, AtomicOrdering::SeqCst);
|
||||
self.step.inner.increment();
|
||||
self.step.can_propose.store(true, AtomicOrdering::SeqCst);
|
||||
if let Some(ref weak) = *self.client.read() {
|
||||
if let Some(c) = weak.upgrade() {
|
||||
c.update_sealing();
|
||||
@@ -778,7 +853,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
|
||||
fn populate_from_parent(&self, header: &mut Header, parent: &Header) {
|
||||
let parent_step = header_step(parent, self.empty_steps_transition).expect("Header has been verified; qed");
|
||||
let current_step = self.step.load();
|
||||
let current_step = self.step.inner.load();
|
||||
|
||||
let current_empty_steps_len = if header.number() >= self.empty_steps_transition {
|
||||
self.empty_steps(parent_step.into(), current_step.into(), parent.hash()).len()
|
||||
@@ -804,7 +879,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
let empty_step: EmptyStep = rlp.as_val().map_err(fmt_err)?;;
|
||||
|
||||
if empty_step.verify(&*self.validators).unwrap_or(false) {
|
||||
if self.step.check_future(empty_step.step).is_ok() {
|
||||
if self.step.inner.check_future(empty_step.step).is_ok() {
|
||||
trace!(target: "engine", "handle_message: received empty step message {:?}", empty_step);
|
||||
self.handle_empty_step_message(empty_step);
|
||||
} else {
|
||||
@@ -824,13 +899,16 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
fn generate_seal(&self, block: &ExecutedBlock, parent: &Header) -> Seal {
|
||||
// first check to avoid generating signature most of the time
|
||||
// (but there's still a race to the `compare_and_swap`)
|
||||
if !self.can_propose.load(AtomicOrdering::SeqCst) { return Seal::None; }
|
||||
if !self.step.can_propose.load(AtomicOrdering::SeqCst) {
|
||||
trace!(target: "engine", "Aborting seal generation. Can't propose.");
|
||||
return Seal::None;
|
||||
}
|
||||
|
||||
let header = block.header();
|
||||
let parent_step: U256 = header_step(parent, self.empty_steps_transition)
|
||||
.expect("Header has been verified; qed").into();
|
||||
|
||||
let step = self.step.load();
|
||||
let step = self.step.inner.load();
|
||||
|
||||
// filter messages from old and future steps and different parents
|
||||
let empty_steps = if header.number() >= self.empty_steps_transition {
|
||||
@@ -852,32 +930,15 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
return Seal::None;
|
||||
}
|
||||
|
||||
// fetch correct validator set for current epoch, taking into account
|
||||
// finality of previous transitions.
|
||||
let active_set;
|
||||
|
||||
let validators = if self.immediate_transitions {
|
||||
&*self.validators
|
||||
} else {
|
||||
let mut epoch_manager = self.epoch_manager.lock();
|
||||
let client = match self.client.read().as_ref().and_then(|weak| weak.upgrade()) {
|
||||
Some(client) => client,
|
||||
None => {
|
||||
warn!(target: "engine", "Unable to generate seal: missing client ref.");
|
||||
return Seal::None;
|
||||
}
|
||||
};
|
||||
|
||||
if !epoch_manager.zoom_to(&*client, &self.machine, &*self.validators, header) {
|
||||
debug!(target: "engine", "Unable to zoom to epoch.");
|
||||
let (validators, set_number) = match self.epoch_set(header) {
|
||||
Err(err) => {
|
||||
warn!(target: "engine", "Unable to generate seal: {}", err);
|
||||
return Seal::None;
|
||||
}
|
||||
|
||||
active_set = epoch_manager.validators().clone();
|
||||
&active_set as &_
|
||||
},
|
||||
Ok(ok) => ok,
|
||||
};
|
||||
|
||||
if is_step_proposer(validators, header.parent_hash(), step, header.author()) {
|
||||
if is_step_proposer(&*validators, header.parent_hash(), step, header.author()) {
|
||||
// this is guarded against by `can_propose` unless the block was signed
|
||||
// on the same step (implies same key) and on a different node.
|
||||
if parent_step == step.into() {
|
||||
@@ -907,10 +968,16 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
trace!(target: "engine", "generate_seal: Issuing a block for step {}.", step);
|
||||
|
||||
// only issue the seal if we were the first to reach the compare_and_swap.
|
||||
if self.can_propose.compare_and_swap(true, false, AtomicOrdering::SeqCst) {
|
||||
|
||||
if self.step.can_propose.compare_and_swap(true, false, AtomicOrdering::SeqCst) {
|
||||
// we can drop all accumulated empty step messages that are
|
||||
// older than the parent step since we're including them in
|
||||
// the seal
|
||||
self.clear_empty_steps(parent_step);
|
||||
|
||||
// report any skipped primaries between the parent block and
|
||||
// the block we're sealing
|
||||
self.report_skipped(header, step, u64::from(parent_step) as usize, &*validators, set_number);
|
||||
|
||||
let mut fields = vec![
|
||||
encode(&step).into_vec(),
|
||||
encode(&(&H520::from(signature) as &[u8])).into_vec(),
|
||||
@@ -985,7 +1052,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
.decode();
|
||||
|
||||
let parent_step = header_step(&parent, self.empty_steps_transition)?;
|
||||
let current_step = self.step.load();
|
||||
let current_step = self.step.inner.load();
|
||||
self.empty_steps(parent_step.into(), current_step.into(), parent.hash())
|
||||
} else {
|
||||
// we're verifying a block, extract empty steps from the seal
|
||||
@@ -1015,13 +1082,21 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
)));
|
||||
}
|
||||
|
||||
// TODO [ToDr] Should this go from epoch manager?
|
||||
// If yes then probably benign reporting needs to be moved further in the verification.
|
||||
let set_number = header.number();
|
||||
|
||||
match verify_timestamp(&*self.step, header_step(header, self.empty_steps_transition)?) {
|
||||
match verify_timestamp(&self.step.inner, header_step(header, self.empty_steps_transition)?) {
|
||||
Err(BlockError::InvalidSeal) => {
|
||||
self.validators.report_benign(header.author(), set_number, header.number());
|
||||
// This check runs in Phase 1 where there is no guarantee that the parent block is
|
||||
// already imported, therefore the call to `epoch_set` may fail. In that case we
|
||||
// won't report the misbehavior but this is not a concern because:
|
||||
// - Only authorities can report and it's expected that they'll be up-to-date and
|
||||
// importing, therefore the parent header will most likely be available
|
||||
// - Even if you are an authority that is syncing the chain, the contract will most
|
||||
// likely ignore old reports
|
||||
// - This specific check is only relevant if you're importing (since it checks
|
||||
// against wall clock)
|
||||
if let Ok((_, set_number)) = self.epoch_set(header) {
|
||||
self.validators.report_benign(header.author(), set_number, header.number());
|
||||
}
|
||||
|
||||
Err(BlockError::InvalidSeal.into())
|
||||
}
|
||||
Err(e) => Err(e.into()),
|
||||
@@ -1033,8 +1108,8 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
fn verify_block_family(&self, header: &Header, parent: &Header) -> Result<(), Error> {
|
||||
let step = header_step(header, self.empty_steps_transition)?;
|
||||
let parent_step = header_step(parent, self.empty_steps_transition)?;
|
||||
// TODO [ToDr] Should this go from epoch manager?
|
||||
let set_number = header.number();
|
||||
|
||||
let (validators, set_number) = self.epoch_set(header)?;
|
||||
|
||||
// Ensure header is from the step after parent.
|
||||
if step == parent_step
|
||||
@@ -1061,7 +1136,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
format!("empty step proof for invalid parent hash: {:?}", empty_step.parent_hash)))?;
|
||||
}
|
||||
|
||||
if !empty_step.verify(&*self.validators).unwrap_or(false) {
|
||||
if !empty_step.verify(&*validators).unwrap_or(false) {
|
||||
Err(EngineError::InsufficientProof(
|
||||
format!("invalid empty step proof: {:?}", empty_step)))?;
|
||||
}
|
||||
@@ -1075,21 +1150,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
}
|
||||
|
||||
} else {
|
||||
// Report skipped primaries.
|
||||
if let (true, Some(me)) = (step > parent_step + 1, self.signer.read().address()) {
|
||||
debug!(target: "engine", "Author {} built block with step gap. current step: {}, parent step: {}",
|
||||
header.author(), step, parent_step);
|
||||
let mut reported = HashSet::new();
|
||||
for s in parent_step + 1..step {
|
||||
let skipped_primary = step_proposer(&*self.validators, &parent.hash(), s);
|
||||
// Do not report this signer.
|
||||
if skipped_primary != me {
|
||||
self.validators.report_benign(&skipped_primary, set_number, header.number());
|
||||
// Stop reporting once validators start repeating.
|
||||
if !reported.insert(skipped_primary) { break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
self.report_skipped(header, step, parent_step, &*validators, set_number);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -1097,37 +1158,21 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
|
||||
// Check the validators.
|
||||
fn verify_block_external(&self, header: &Header) -> Result<(), Error> {
|
||||
// fetch correct validator set for current epoch, taking into account
|
||||
// finality of previous transitions.
|
||||
let active_set;
|
||||
let validators = if self.immediate_transitions {
|
||||
&*self.validators
|
||||
} else {
|
||||
// get correct validator set for epoch.
|
||||
let client = match self.client.read().as_ref().and_then(|weak| weak.upgrade()) {
|
||||
Some(client) => client,
|
||||
None => {
|
||||
debug!(target: "engine", "Unable to verify sig: missing client ref.");
|
||||
return Err(EngineError::RequiresClient.into())
|
||||
}
|
||||
};
|
||||
|
||||
let mut epoch_manager = self.epoch_manager.lock();
|
||||
if !epoch_manager.zoom_to(&*client, &self.machine, &*self.validators, header) {
|
||||
debug!(target: "engine", "Unable to zoom to epoch.");
|
||||
return Err(EngineError::RequiresClient.into())
|
||||
}
|
||||
|
||||
active_set = epoch_manager.validators().clone();
|
||||
&active_set as &_
|
||||
};
|
||||
let (validators, set_number) = self.epoch_set(header)?;
|
||||
|
||||
// verify signature against fixed list, but reports should go to the
|
||||
// contract itself.
|
||||
let res = verify_external(header, validators, self.empty_steps_transition);
|
||||
if res.is_ok() {
|
||||
let header_step = header_step(header, self.empty_steps_transition)?;
|
||||
self.clear_empty_steps(header_step.into());
|
||||
let res = verify_external(header, &*validators, self.empty_steps_transition);
|
||||
match res {
|
||||
Err(Error::Engine(EngineError::NotProposer(_))) => {
|
||||
self.validators.report_benign(header.author(), set_number, header.number());
|
||||
},
|
||||
Ok(_) => {
|
||||
// we can drop all accumulated empty step messages that are older than this header's step
|
||||
let header_step = header_step(header, self.empty_steps_transition)?;
|
||||
self.clear_empty_steps(header_step.into());
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
res
|
||||
}
|
||||
@@ -1261,7 +1306,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
// This way, upon encountering an epoch change, the proposer from the
|
||||
// new set will be forced to wait until the next step to avoid sealing a
|
||||
// block that breaks the invariant that the parent's step < the block's step.
|
||||
self.can_propose.store(false, AtomicOrdering::SeqCst);
|
||||
self.step.can_propose.store(false, AtomicOrdering::SeqCst);
|
||||
return Some(combine_proofs(signal_number, &pending.proof, &*finality_proof));
|
||||
}
|
||||
}
|
||||
@@ -1527,7 +1572,6 @@ mod tests {
|
||||
parent_header.set_seal(vec![encode(&1usize).into_vec()]);
|
||||
parent_header.set_gas_limit("222222".parse::<U256>().unwrap());
|
||||
let mut header: Header = Header::default();
|
||||
header.set_number(1);
|
||||
header.set_gas_limit("222222".parse::<U256>().unwrap());
|
||||
header.set_seal(vec![encode(&3usize).into_vec()]);
|
||||
|
||||
@@ -1537,8 +1581,15 @@ mod tests {
|
||||
|
||||
aura.set_signer(Arc::new(AccountProvider::transient_provider()), Default::default(), Default::default());
|
||||
|
||||
// Do not report on steps skipped between genesis and first block.
|
||||
header.set_number(1);
|
||||
assert!(aura.verify_block_family(&header, &parent_header).is_ok());
|
||||
assert_eq!(last_benign.load(AtomicOrdering::SeqCst), 1);
|
||||
assert_eq!(last_benign.load(AtomicOrdering::SeqCst), 0);
|
||||
|
||||
// Report on skipped steps otherwise.
|
||||
header.set_number(2);
|
||||
assert!(aura.verify_block_family(&header, &parent_header).is_ok());
|
||||
assert_eq!(last_benign.load(AtomicOrdering::SeqCst), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -55,7 +55,7 @@ pub fn new_validator_set(spec: ValidatorSpec) -> Box<ValidatorSet> {
|
||||
}
|
||||
|
||||
/// A validator set.
|
||||
pub trait ValidatorSet: Send + Sync {
|
||||
pub trait ValidatorSet: Send + Sync + 'static {
|
||||
/// Get the default "Call" helper, for use in general operation.
|
||||
// TODO [keorn]: this is a hack intended to migrate off of
|
||||
// a strict dependency on state always being available.
|
||||
|
||||
@@ -104,6 +104,12 @@ impl ValidatorSet for SimpleList {
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<ValidatorSet> for SimpleList {
|
||||
fn as_ref(&self) -> &ValidatorSet {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::str::FromStr;
|
||||
|
||||
@@ -61,6 +61,11 @@ pub fn new_expanse<'a, T: Into<SpecParams<'a>>>(params: T) -> Spec {
|
||||
load(params.into(), include_bytes!("../../res/ethereum/expanse.json"))
|
||||
}
|
||||
|
||||
/// Create a new Tobalaba chain spec.
|
||||
pub fn new_tobalaba<'a, T: Into<SpecParams<'a>>>(params: T) -> Spec {
|
||||
load(params.into(), include_bytes!("../../res/ethereum/tobalaba.json"))
|
||||
}
|
||||
|
||||
/// Create a new Musicoin mainnet chain spec.
|
||||
pub fn new_musicoin<'a, T: Into<SpecParams<'a>>>(params: T) -> Spec {
|
||||
load(params.into(), include_bytes!("../../res/ethereum/musicoin.json"))
|
||||
@@ -91,6 +96,9 @@ pub fn new_morden<'a, T: Into<SpecParams<'a>>>(params: T) -> Spec {
|
||||
/// Create a new Foundation Frontier-era chain spec as though it never changes to Homestead.
|
||||
pub fn new_frontier_test() -> Spec { load(None, include_bytes!("../../res/ethereum/frontier_test.json")) }
|
||||
|
||||
/// Create a new Ropsten chain spec.
|
||||
pub fn new_ropsten_test() -> Spec { load(None, include_bytes!("../../res/ethereum/ropsten.json")) }
|
||||
|
||||
/// Create a new Foundation Homestead-era chain spec as though it never changed from Frontier.
|
||||
pub fn new_homestead_test() -> Spec { load(None, include_bytes!("../../res/ethereum/homestead_test.json")) }
|
||||
|
||||
|
||||
@@ -428,8 +428,14 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
||||
self.state.discard_checkpoint();
|
||||
output.write(0, &builtin_out_buffer);
|
||||
|
||||
// trace only top level calls to builtins to avoid DDoS attacks
|
||||
if self.depth == 0 {
|
||||
// Trace only top level calls and calls with balance transfer to builtins. The reason why we don't
|
||||
// trace all internal calls to builtin contracts is that memcpy (IDENTITY) is a heavily used
|
||||
// function.
|
||||
let is_transferred = match params.value {
|
||||
ActionValue::Transfer(value) => value != U256::zero(),
|
||||
ActionValue::Apparent(_) => false,
|
||||
};
|
||||
if self.depth == 0 || is_transferred {
|
||||
let mut trace_output = tracer.prepare_trace_output();
|
||||
if let Some(out) = trace_output.as_mut() {
|
||||
*out = output.to_owned();
|
||||
@@ -722,6 +728,12 @@ mod tests {
|
||||
machine
|
||||
}
|
||||
|
||||
fn make_byzantium_machine(max_depth: usize) -> EthereumMachine {
|
||||
let mut machine = ::ethereum::new_byzantium_test_machine();
|
||||
machine.set_schedule_creation_rules(Box::new(move |s, _| s.max_depth = max_depth));
|
||||
machine
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_contract_address() {
|
||||
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||
@@ -814,6 +826,76 @@ mod tests {
|
||||
assert_eq!(substate.contracts_created.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_call_to_precompiled_tracing() {
|
||||
// code:
|
||||
//
|
||||
// 60 00 - push 00 out size
|
||||
// 60 00 - push 00 out offset
|
||||
// 60 00 - push 00 in size
|
||||
// 60 00 - push 00 in offset
|
||||
// 60 01 - push 01 value
|
||||
// 60 03 - push 03 to
|
||||
// 61 ffff - push fff gas
|
||||
// f1 - CALL
|
||||
|
||||
let code = "60006000600060006001600361fffff1".from_hex().unwrap();
|
||||
let sender = Address::from_str("4444444444444444444444444444444444444444").unwrap();
|
||||
let address = Address::from_str("5555555555555555555555555555555555555555").unwrap();
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.address = address.clone();
|
||||
params.code_address = address.clone();
|
||||
params.sender = sender.clone();
|
||||
params.origin = sender.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.value = ActionValue::Transfer(U256::from(100));
|
||||
params.call_type = CallType::Call;
|
||||
let mut state = get_temp_state();
|
||||
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap();
|
||||
let info = EnvInfo::default();
|
||||
let machine = make_byzantium_machine(5);
|
||||
let mut substate = Substate::new();
|
||||
let mut tracer = ExecutiveTracer::default();
|
||||
let mut vm_tracer = ExecutiveVMTracer::toplevel();
|
||||
|
||||
let mut ex = Executive::new(&mut state, &info, &machine);
|
||||
let output = BytesRef::Fixed(&mut[0u8;0]);
|
||||
ex.call(params, &mut substate, output, &mut tracer, &mut vm_tracer).unwrap();
|
||||
|
||||
assert_eq!(tracer.drain(), vec![FlatTrace {
|
||||
action: trace::Action::Call(trace::Call {
|
||||
from: "4444444444444444444444444444444444444444".into(),
|
||||
to: "5555555555555555555555555555555555555555".into(),
|
||||
value: 100.into(),
|
||||
gas: 100_000.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: 33021.into(),
|
||||
output: vec![]
|
||||
}),
|
||||
subtraces: 1,
|
||||
trace_address: Default::default()
|
||||
}, FlatTrace {
|
||||
action: trace::Action::Call(trace::Call {
|
||||
from: "5555555555555555555555555555555555555555".into(),
|
||||
to: "0000000000000000000000000000000000000003".into(),
|
||||
value: 1.into(),
|
||||
gas: 66560.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call
|
||||
}), result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: 600.into(),
|
||||
output: vec![]
|
||||
}),
|
||||
subtraces: 0,
|
||||
trace_address: vec![0].into_iter().collect(),
|
||||
}]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Tracing is not suported in JIT
|
||||
fn test_call_to_create() {
|
||||
|
||||
@@ -473,6 +473,30 @@ fn round_block_gas_limit(gas_limit: U256, lower_limit: U256, upper_limit: U256)
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn should_disallow_unsigned_transactions() {
|
||||
use tests::helpers::get_default_ethash_extensions;
|
||||
|
||||
let rlp = "ea80843b9aca0083015f90948921ebb5f79e9e3920abe571004d0b1d5119c154865af3107a400080038080".into();
|
||||
let transaction: UnverifiedTransaction = ::rlp::decode(&::rustc_hex::FromHex::from_hex(rlp).unwrap());
|
||||
let spec = ::ethereum::new_ropsten_test();
|
||||
let ethparams = get_default_ethash_extensions();
|
||||
|
||||
let machine = EthereumMachine::with_ethash_extensions(
|
||||
spec.params().clone(),
|
||||
Default::default(),
|
||||
ethparams,
|
||||
);
|
||||
let mut header = ::header::Header::new();
|
||||
header.set_number(15);
|
||||
|
||||
let res = machine.verify_transaction_basic(&transaction, &header);
|
||||
match res {
|
||||
Err(Error::Transaction(transaction::Error::InvalidSignature(_))) => (),
|
||||
e => panic!("Expected: Transaction Invalid Signature, Got: {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ethash_gas_limit_is_multiple_of_determinant() {
|
||||
use ethereum_types::U256;
|
||||
|
||||
@@ -709,7 +709,7 @@ impl Spec {
|
||||
author: *genesis.author(),
|
||||
timestamp: genesis.timestamp(),
|
||||
difficulty: *genesis.difficulty(),
|
||||
gas_limit: *genesis.gas_limit(),
|
||||
gas_limit: U256::max_value(),
|
||||
last_hashes: Arc::new(Vec::new()),
|
||||
gas_used: 0.into(),
|
||||
};
|
||||
@@ -718,7 +718,7 @@ impl Spec {
|
||||
let tx = Transaction {
|
||||
nonce: self.engine.account_start_nonce(0),
|
||||
action: Action::Call(a),
|
||||
gas: U256::from(50_000_000), // TODO: share with client.
|
||||
gas: U256::max_value(),
|
||||
gas_price: U256::default(),
|
||||
value: U256::default(),
|
||||
data: d,
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
use std::cell::{RefCell, RefMut};
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::{HashMap, BTreeMap, HashSet};
|
||||
use std::collections::{HashMap, BTreeMap, BTreeSet, HashSet};
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY};
|
||||
@@ -833,40 +833,65 @@ impl<B: Backend> State<B> {
|
||||
}))
|
||||
}
|
||||
|
||||
// Return a list of all touched addresses in cache.
|
||||
fn touched_addresses(&self) -> Vec<Address> {
|
||||
/// Populate a PodAccount map from this state, with another state as the account and storage query.
|
||||
pub fn to_pod_diff<X: Backend>(&mut self, query: &State<X>) -> trie::Result<PodState> {
|
||||
assert!(self.checkpoints.borrow().is_empty());
|
||||
self.cache.borrow().iter().map(|(add, _)| *add).collect()
|
||||
}
|
||||
|
||||
fn query_pod(&mut self, query: &PodState, touched_addresses: &[Address]) -> trie::Result<()> {
|
||||
let pod = query.get();
|
||||
// Merge PodAccount::to_pod for cache of self and `query`.
|
||||
let all_addresses = self.cache.borrow().keys().cloned()
|
||||
.chain(query.cache.borrow().keys().cloned())
|
||||
.collect::<BTreeSet<_>>();
|
||||
|
||||
for address in touched_addresses {
|
||||
if !self.ensure_cached(address, RequireCache::Code, true, |a| a.is_some())? {
|
||||
continue
|
||||
Ok(PodState::from(all_addresses.into_iter().fold(Ok(BTreeMap::new()), |m: trie::Result<_>, address| {
|
||||
let mut m = m?;
|
||||
|
||||
let account = self.ensure_cached(&address, RequireCache::Code, true, |acc| {
|
||||
acc.map(|acc| {
|
||||
// Merge all modified storage keys.
|
||||
let all_keys = {
|
||||
let self_keys = acc.storage_changes().keys().cloned()
|
||||
.collect::<BTreeSet<_>>();
|
||||
|
||||
if let Some(ref query_storage) = query.cache.borrow().get(&address)
|
||||
.and_then(|opt| {
|
||||
Some(opt.account.as_ref()?.storage_changes().keys().cloned()
|
||||
.collect::<BTreeSet<_>>())
|
||||
})
|
||||
{
|
||||
self_keys.union(&query_storage).cloned().collect::<Vec<_>>()
|
||||
} else {
|
||||
self_keys.into_iter().collect::<Vec<_>>()
|
||||
}
|
||||
};
|
||||
|
||||
// Storage must be fetched after ensure_cached to avoid borrow problem.
|
||||
(*acc.balance(), *acc.nonce(), all_keys, acc.code().map(|x| x.to_vec()))
|
||||
})
|
||||
})?;
|
||||
|
||||
if let Some((balance, nonce, storage_keys, code)) = account {
|
||||
let storage = storage_keys.into_iter().fold(Ok(BTreeMap::new()), |s: trie::Result<_>, key| {
|
||||
let mut s = s?;
|
||||
|
||||
s.insert(key, self.storage_at(&address, &key)?);
|
||||
Ok(s)
|
||||
})?;
|
||||
|
||||
m.insert(address, PodAccount {
|
||||
balance, nonce, storage, code
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(pod_account) = pod.get(address) {
|
||||
// needs to be split into two parts for the refcell code here
|
||||
// to work.
|
||||
for key in pod_account.storage.keys() {
|
||||
self.storage_at(address, key)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(m)
|
||||
})?))
|
||||
}
|
||||
|
||||
/// Returns a `StateDiff` describing the difference from `orig` to `self`.
|
||||
/// Consumes self.
|
||||
pub fn diff_from<X: Backend>(&self, orig: State<X>) -> trie::Result<StateDiff> {
|
||||
let addresses_post = self.touched_addresses();
|
||||
pub fn diff_from<X: Backend>(&self, mut orig: State<X>) -> trie::Result<StateDiff> {
|
||||
let pod_state_post = self.to_pod();
|
||||
let mut state_pre = orig;
|
||||
state_pre.query_pod(&pod_state_post, &addresses_post)?;
|
||||
Ok(pod_state::diff_pod(&state_pre.to_pod(), &pod_state_post))
|
||||
let pod_state_pre = orig.to_pod_diff(self)?;
|
||||
Ok(pod_state::diff_pod(&pod_state_pre, &pod_state_post))
|
||||
}
|
||||
|
||||
// load required account data from the databases.
|
||||
@@ -2209,9 +2234,6 @@ mod tests {
|
||||
let original = state.clone();
|
||||
state.kill_account(&a);
|
||||
|
||||
assert_eq!(original.touched_addresses(), vec![]);
|
||||
assert_eq!(state.touched_addresses(), vec![a]);
|
||||
|
||||
let diff = state.diff_from(original).unwrap();
|
||||
let diff_map = diff.get();
|
||||
assert_eq!(diff_map.len(), 1);
|
||||
@@ -2224,4 +2246,42 @@ mod tests {
|
||||
storage: Default::default()
|
||||
}), None).as_ref());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_trace_diff_unmodified_storage() {
|
||||
use pod_account;
|
||||
|
||||
let a = 10.into();
|
||||
let db = get_temp_state_db();
|
||||
|
||||
let (root, db) = {
|
||||
let mut state = State::new(db, U256::from(0), Default::default());
|
||||
state.set_storage(&a, H256::from(&U256::from(1u64)), H256::from(&U256::from(20u64))).unwrap();
|
||||
state.commit().unwrap();
|
||||
state.drop()
|
||||
};
|
||||
|
||||
let mut state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
|
||||
let original = state.clone();
|
||||
state.set_storage(&a, H256::from(&U256::from(1u64)), H256::from(&U256::from(100u64))).unwrap();
|
||||
|
||||
let diff = state.diff_from(original).unwrap();
|
||||
let diff_map = diff.get();
|
||||
assert_eq!(diff_map.len(), 1);
|
||||
assert!(diff_map.get(&a).is_some());
|
||||
assert_eq!(diff_map.get(&a),
|
||||
pod_account::diff_pod(Some(&PodAccount {
|
||||
balance: U256::zero(),
|
||||
nonce: U256::zero(),
|
||||
code: Some(Default::default()),
|
||||
storage: vec![(H256::from(&U256::from(1u64)), H256::from(&U256::from(20u64)))]
|
||||
.into_iter().collect(),
|
||||
}), Some(&PodAccount {
|
||||
balance: U256::zero(),
|
||||
nonce: U256::zero(),
|
||||
code: Some(Default::default()),
|
||||
storage: vec![(H256::from(&U256::from(1u64)), H256::from(&U256::from(100u64)))]
|
||||
.into_iter().collect(),
|
||||
})).as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,6 +340,7 @@ mod tests {
|
||||
use hash::keccak;
|
||||
use engines::EthEngine;
|
||||
use error::BlockError::*;
|
||||
use error::Error;
|
||||
use ethkey::{Random, Generator};
|
||||
use spec::{CommonParams, Spec};
|
||||
use tests::helpers::{create_test_block_with_data, create_test_block};
|
||||
@@ -458,7 +459,7 @@ mod tests {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn logs<F>(&self, _blocks: Vec<BlockNumber>, _matches: F, _limit: Option<usize>) -> Vec<LocalizedLogEntry>
|
||||
fn logs<F>(&self, _blocks: Vec<H256>, _matches: F, _limit: Option<usize>) -> Vec<LocalizedLogEntry>
|
||||
where F: Fn(&LogEntry) -> bool, Self: Sized {
|
||||
unimplemented!()
|
||||
}
|
||||
@@ -556,7 +557,17 @@ mod tests {
|
||||
nonce: U256::from(2)
|
||||
}.sign(keypair.secret(), None);
|
||||
|
||||
let tr3 = Transaction {
|
||||
action: Action::Call(0x0.into()),
|
||||
value: U256::from(0),
|
||||
data: Bytes::new(),
|
||||
gas: U256::from(30_000),
|
||||
gas_price: U256::from(0),
|
||||
nonce: U256::zero(),
|
||||
}.null_sign(0);
|
||||
|
||||
let good_transactions = [ tr1.clone(), tr2.clone() ];
|
||||
let eip86_transactions = [ tr3.clone() ];
|
||||
|
||||
let diff_inc = U256::from(0x40);
|
||||
|
||||
@@ -592,6 +603,7 @@ mod tests {
|
||||
uncles_rlp.append_list(&good_uncles);
|
||||
let good_uncles_hash = keccak(uncles_rlp.as_raw());
|
||||
let good_transactions_root = ordered_trie_root(good_transactions.iter().map(|t| ::rlp::encode::<UnverifiedTransaction>(t)));
|
||||
let eip86_transactions_root = ordered_trie_root(eip86_transactions.iter().map(|t| ::rlp::encode::<UnverifiedTransaction>(t)));
|
||||
|
||||
let mut parent = good.clone();
|
||||
parent.set_number(9);
|
||||
@@ -612,6 +624,14 @@ mod tests {
|
||||
|
||||
check_ok(basic_test(&create_test_block(&good), engine));
|
||||
|
||||
let mut bad_header = good.clone();
|
||||
bad_header.set_transactions_root(eip86_transactions_root.clone());
|
||||
bad_header.set_uncles_hash(good_uncles_hash.clone());
|
||||
match basic_test(&create_test_block_with_data(&bad_header, &eip86_transactions, &good_uncles), engine) {
|
||||
Err(Error::Transaction(ref e)) if e == &::ethkey::Error::InvalidSignature.into() => (),
|
||||
e => panic!("Block verification failed.\nExpected: Transaction Error (Invalid Signature)\nGot: {:?}", e),
|
||||
}
|
||||
|
||||
let mut header = good.clone();
|
||||
header.set_transactions_root(good_transactions_root.clone());
|
||||
header.set_uncles_hash(good_uncles_hash.clone());
|
||||
|
||||
@@ -392,6 +392,10 @@ impl UnverifiedTransaction {
|
||||
if check_low_s && !(allow_empty_signature && self.is_unsigned()) {
|
||||
self.check_low_s()?;
|
||||
}
|
||||
// Disallow unsigned transactions in case EIP-86 is disabled.
|
||||
if !allow_empty_signature && self.is_unsigned() {
|
||||
return Err(ethkey::Error::InvalidSignature.into());
|
||||
}
|
||||
// EIP-86: Transactions of this form MUST have gasprice = 0, nonce = 0, value = 0, and do NOT increment the nonce of account 0.
|
||||
if allow_empty_signature && self.is_unsigned() && !(self.gas_price.is_zero() && self.value.is_zero() && self.nonce.is_zero()) {
|
||||
return Err(ethkey::Error::InvalidSignature.into())
|
||||
|
||||
@@ -11,5 +11,5 @@ parity-wasm = "0.27"
|
||||
libc = "0.2"
|
||||
pwasm-utils = "0.1"
|
||||
vm = { path = "../vm" }
|
||||
wasmi = { version = "0.1.3", features = ["opt-in-32bit"] }
|
||||
ethcore-logger = { path = "../../logger" }
|
||||
wasmi = { version = "0.2" }
|
||||
|
||||
@@ -71,7 +71,7 @@ pub fn setup_log(config: &Config) -> Result<Arc<RotatingLogger>, String> {
|
||||
builder.filter(Some("ws"), LogLevelFilter::Warn);
|
||||
builder.filter(Some("reqwest"), LogLevelFilter::Warn);
|
||||
builder.filter(Some("hyper"), LogLevelFilter::Warn);
|
||||
builder.filter(Some("rustls"), LogLevelFilter::Warn);
|
||||
builder.filter(Some("rustls"), LogLevelFilter::Error);
|
||||
// Enable info for others.
|
||||
builder.filter(None, LogLevelFilter::Info);
|
||||
|
||||
|
||||
@@ -462,7 +462,7 @@
|
||||
<key>OVERWRITE_PERMISSIONS</key>
|
||||
<false/>
|
||||
<key>VERSION</key>
|
||||
<string>1.10.3</string>
|
||||
<string>1.10.9</string>
|
||||
</dict>
|
||||
<key>UUID</key>
|
||||
<string>2DCD5B81-7BAF-4DA1-9251-6274B089FD36</string>
|
||||
|
||||
@@ -3,6 +3,4 @@
|
||||
test -f /usr/local/libexec/uninstall-parity.sh && /usr/local/libexec/uninstall-parity.sh || true
|
||||
killall -9 parity && sleep 5
|
||||
su $USER -c "open /Applications/Parity\ Ethereum.app"
|
||||
sleep 5
|
||||
su $USER -c "open http://127.0.0.1:8180/"
|
||||
exit 0
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
!define DESCRIPTION "Fast, light, robust Ethereum implementation"
|
||||
!define VERSIONMAJOR 1
|
||||
!define VERSIONMINOR 10
|
||||
!define VERSIONBUILD 3
|
||||
!define VERSIONBUILD 9
|
||||
!define ARGS ""
|
||||
!define FIRST_START_ARGS "--mode=passive ui"
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ fn new(n: NewAccount) -> Result<String, String> {
|
||||
let secret_store = Box::new(secret_store(dir, Some(n.iterations))?);
|
||||
let acc_provider = AccountProvider::new(secret_store, AccountProviderSettings::default());
|
||||
let new_account = acc_provider.new_account(&password).map_err(|e| format!("Could not create new account: {}", e))?;
|
||||
Ok(format!("0x{:?}", new_account))
|
||||
Ok(format!("0x{:x}", new_account))
|
||||
}
|
||||
|
||||
fn list(list_cmd: ListAccounts) -> Result<String, String> {
|
||||
@@ -103,7 +103,7 @@ fn list(list_cmd: ListAccounts) -> Result<String, String> {
|
||||
let acc_provider = AccountProvider::new(secret_store, AccountProviderSettings::default());
|
||||
let accounts = acc_provider.accounts().map_err(|e| format!("{}", e))?;
|
||||
let result = accounts.into_iter()
|
||||
.map(|a| format!("0x{:?}", a))
|
||||
.map(|a| format!("0x{:x}", a))
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n");
|
||||
|
||||
|
||||
@@ -277,7 +277,7 @@ usage! {
|
||||
|
||||
ARG arg_chain: (String) = "foundation", or |c: &Config| c.parity.as_ref()?.chain.clone(),
|
||||
"--chain=[CHAIN]",
|
||||
"Specify the blockchain type. CHAIN may be either a JSON chain specification file or olympic, frontier, homestead, mainnet, morden, ropsten, classic, expanse, musicoin, ellaism, testnet, kovan or dev.",
|
||||
"Specify the blockchain type. CHAIN may be either a JSON chain specification file or olympic, frontier, homestead, mainnet, morden, ropsten, classic, expanse, tobalaba, musicoin, ellaism, testnet, kovan or dev.",
|
||||
|
||||
ARG arg_keys_path: (String) = "$BASE/keys", or |c: &Config| c.parity.as_ref()?.keys_path.clone(),
|
||||
"--keys-path=[PATH]",
|
||||
|
||||
@@ -32,6 +32,7 @@ pub enum SpecType {
|
||||
Foundation,
|
||||
Morden,
|
||||
Ropsten,
|
||||
Tobalaba,
|
||||
Kovan,
|
||||
Olympic,
|
||||
Classic,
|
||||
@@ -58,6 +59,7 @@ impl str::FromStr for SpecType {
|
||||
"morden" | "classic-testnet" => SpecType::Morden,
|
||||
"ropsten" => SpecType::Ropsten,
|
||||
"kovan" | "testnet" => SpecType::Kovan,
|
||||
"tobalaba" => SpecType::Tobalaba,
|
||||
"olympic" => SpecType::Olympic,
|
||||
"expanse" => SpecType::Expanse,
|
||||
"musicoin" => SpecType::Musicoin,
|
||||
@@ -81,6 +83,7 @@ impl fmt::Display for SpecType {
|
||||
SpecType::Musicoin => "musicoin",
|
||||
SpecType::Ellaism => "ellaism",
|
||||
SpecType::Kovan => "kovan",
|
||||
SpecType::Tobalaba => "tobalaba",
|
||||
SpecType::Dev => "dev",
|
||||
SpecType::Custom(ref custom) => custom,
|
||||
})
|
||||
@@ -99,6 +102,7 @@ impl SpecType {
|
||||
SpecType::Expanse => Ok(ethereum::new_expanse(params)),
|
||||
SpecType::Musicoin => Ok(ethereum::new_musicoin(params)),
|
||||
SpecType::Ellaism => Ok(ethereum::new_ellaism(params)),
|
||||
SpecType::Tobalaba => Ok(ethereum::new_tobalaba(params)),
|
||||
SpecType::Kovan => Ok(ethereum::new_kovan(params)),
|
||||
SpecType::Dev => Ok(Spec::new_instant()),
|
||||
SpecType::Custom(ref filename) => {
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use transaction::{Transaction, SignedTransaction, Action};
|
||||
use ethereum_types::U256;
|
||||
|
||||
use jsonrpc_core::Error;
|
||||
use v1::helpers::CallRequest;
|
||||
@@ -29,7 +28,7 @@ pub fn sign_call(request: CallRequest, gas_cap: bool) -> Result<SignedTransactio
|
||||
}
|
||||
Some(gas) => gas,
|
||||
None if gas_cap => max_gas,
|
||||
None => U256::from(2) << 50,
|
||||
None => max_gas * 10,
|
||||
};
|
||||
let from = request.from.unwrap_or(0.into());
|
||||
|
||||
|
||||
@@ -129,9 +129,8 @@ impl LightFetch {
|
||||
}
|
||||
}
|
||||
BlockId::Hash(h) => {
|
||||
reqs.push(request::HeaderByHash(h.into()).into());
|
||||
|
||||
let idx = reqs.len();
|
||||
reqs.push(request::HeaderByHash(h.into()).into());
|
||||
Ok(HeaderRef::Unresolved(idx, h.into()))
|
||||
}
|
||||
_ => Err(errors::unknown_block()) // latest, earliest, and pending will have all already returned.
|
||||
|
||||
@@ -45,7 +45,7 @@ pub use self::requests::{
|
||||
TransactionRequest, FilledTransactionRequest, ConfirmationRequest, ConfirmationPayload, CallRequest,
|
||||
};
|
||||
pub use self::signing_queue::{
|
||||
ConfirmationsQueue, ConfirmationReceiver, ConfirmationResult,
|
||||
ConfirmationsQueue, ConfirmationReceiver, ConfirmationResult, ConfirmationSender,
|
||||
SigningQueue, QueueEvent, DefaultAccount,
|
||||
QUEUE_LIMIT as SIGNING_QUEUE_LIMIT,
|
||||
};
|
||||
|
||||
@@ -75,16 +75,17 @@ pub trait SigningQueue: Send + Sync {
|
||||
/// `ConfirmationReceiver` is a `Future` awaiting for resolution of the given request.
|
||||
fn add_request(&self, request: ConfirmationPayload, origin: Origin) -> Result<(U256, ConfirmationReceiver), QueueAddError>;
|
||||
|
||||
/// Removes a request from the queue.
|
||||
/// Notifies possible token holders that request was rejected.
|
||||
fn request_rejected(&self, id: U256) -> Option<ConfirmationRequest>;
|
||||
fn request_rejected(&self, sender: ConfirmationSender) -> Option<ConfirmationRequest>;
|
||||
|
||||
/// Removes a request from the queue.
|
||||
/// Notifies possible token holders that request was confirmed and given hash was assigned.
|
||||
fn request_confirmed(&self, id: U256, result: ConfirmationResult) -> Option<ConfirmationRequest>;
|
||||
fn request_confirmed(&self, sender: ConfirmationSender, result: ConfirmationResult) -> Option<ConfirmationRequest>;
|
||||
|
||||
/// Returns a request if it is contained in the queue.
|
||||
fn peek(&self, id: &U256) -> Option<ConfirmationRequest>;
|
||||
/// Put a request taken from `SigningQueue::take` back to the queue.
|
||||
fn request_untouched(&self, sender: ConfirmationSender);
|
||||
|
||||
/// Returns and removes a request if it is contained in the queue.
|
||||
fn take(&self, id: &U256) -> Option<ConfirmationSender>;
|
||||
|
||||
/// Return copy of all the requests in the queue.
|
||||
fn requests(&self) -> Vec<ConfirmationRequest>;
|
||||
@@ -96,9 +97,12 @@ pub trait SigningQueue: Send + Sync {
|
||||
fn is_empty(&self) -> bool;
|
||||
}
|
||||
|
||||
struct ConfirmationSender {
|
||||
/// Confirmation request information with result notifier.
|
||||
pub struct ConfirmationSender {
|
||||
/// Confirmation request information.
|
||||
pub request: ConfirmationRequest,
|
||||
|
||||
sender: oneshot::Sender<ConfirmationResult>,
|
||||
request: ConfirmationRequest,
|
||||
}
|
||||
|
||||
/// Receiving end of the Confirmation channel; can be used as a `Future` to await for `ConfirmationRequest`
|
||||
@@ -122,36 +126,29 @@ impl ConfirmationsQueue {
|
||||
/// Notifies consumer that the communcation is over.
|
||||
/// No more events will be sent after this function is invoked.
|
||||
pub fn finish(&self) {
|
||||
self.notify(QueueEvent::Finish);
|
||||
self.notify_message(QueueEvent::Finish);
|
||||
self.on_event.write().clear();
|
||||
}
|
||||
|
||||
/// Notifies receiver about the event happening in this queue.
|
||||
fn notify(&self, message: QueueEvent) {
|
||||
for listener in &*self.on_event.read() {
|
||||
listener(message.clone())
|
||||
}
|
||||
/// Notifies `ConfirmationReceiver` holder about the result given a request.
|
||||
fn notify_result(&self, sender: ConfirmationSender, result: Option<ConfirmationResult>) -> Option<ConfirmationRequest> {
|
||||
// notify receiver about the event
|
||||
self.notify_message(result.clone().map_or_else(
|
||||
|| QueueEvent::RequestRejected(sender.request.id),
|
||||
|_| QueueEvent::RequestConfirmed(sender.request.id)
|
||||
));
|
||||
|
||||
// notify confirmation receiver about resolution
|
||||
let result = result.ok_or(errors::request_rejected());
|
||||
sender.sender.send(result);
|
||||
|
||||
Some(sender.request)
|
||||
}
|
||||
|
||||
/// Removes requests from this queue and notifies `ConfirmationReceiver` holder about the result.
|
||||
/// Notifies also a receiver about that event.
|
||||
fn remove(&self, id: U256, result: Option<ConfirmationResult>) -> Option<ConfirmationRequest> {
|
||||
let sender = self.queue.write().remove(&id);
|
||||
|
||||
if let Some(sender) = sender {
|
||||
// notify receiver about the event
|
||||
self.notify(result.clone().map_or_else(
|
||||
|| QueueEvent::RequestRejected(id),
|
||||
|_| QueueEvent::RequestConfirmed(id)
|
||||
));
|
||||
|
||||
// notify confirmation receiver about resolution
|
||||
let result = result.ok_or(errors::request_rejected());
|
||||
sender.sender.send(result);
|
||||
|
||||
Some(sender.request)
|
||||
} else {
|
||||
None
|
||||
/// Notifies receiver about the event happening in this queue.
|
||||
fn notify_message(&self, message: QueueEvent) {
|
||||
for listener in &*self.on_event.read() {
|
||||
listener(message.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,22 +190,26 @@ impl SigningQueue for ConfirmationsQueue {
|
||||
(id, receiver)
|
||||
};
|
||||
// Notify listeners
|
||||
self.notify(QueueEvent::NewRequest(id));
|
||||
self.notify_message(QueueEvent::NewRequest(id));
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn peek(&self, id: &U256) -> Option<ConfirmationRequest> {
|
||||
self.queue.read().get(id).map(|sender| sender.request.clone())
|
||||
fn take(&self, id: &U256) -> Option<ConfirmationSender> {
|
||||
self.queue.write().remove(id)
|
||||
}
|
||||
|
||||
fn request_rejected(&self, id: U256) -> Option<ConfirmationRequest> {
|
||||
debug!(target: "own_tx", "Signer: Request rejected ({:?}).", id);
|
||||
self.remove(id, None)
|
||||
fn request_rejected(&self, sender: ConfirmationSender) -> Option<ConfirmationRequest> {
|
||||
debug!(target: "own_tx", "Signer: Request rejected ({:?}).", sender.request.id);
|
||||
self.notify_result(sender, None)
|
||||
}
|
||||
|
||||
fn request_confirmed(&self, id: U256, result: ConfirmationResult) -> Option<ConfirmationRequest> {
|
||||
debug!(target: "own_tx", "Signer: Transaction confirmed ({:?}).", id);
|
||||
self.remove(id, Some(result))
|
||||
fn request_confirmed(&self, sender: ConfirmationSender, result: ConfirmationResult) -> Option<ConfirmationRequest> {
|
||||
debug!(target: "own_tx", "Signer: Request confirmed ({:?}).", sender.request.id);
|
||||
self.notify_result(sender, Some(result))
|
||||
}
|
||||
|
||||
fn request_untouched(&self, sender: ConfirmationSender) {
|
||||
self.queue.write().insert(sender.request.id, sender);
|
||||
}
|
||||
|
||||
fn requests(&self) -> Vec<ConfirmationRequest> {
|
||||
@@ -261,7 +262,8 @@ mod test {
|
||||
|
||||
// when
|
||||
let (id, future) = queue.add_request(request, Default::default()).unwrap();
|
||||
queue.request_confirmed(id, Ok(ConfirmationResponse::SendTransaction(1.into())));
|
||||
let sender = queue.take(&id).unwrap();
|
||||
queue.request_confirmed(sender, Ok(ConfirmationResponse::SendTransaction(1.into())));
|
||||
|
||||
// then
|
||||
let confirmation = future.wait().unwrap();
|
||||
|
||||
@@ -92,11 +92,11 @@ impl<D: Dispatcher + 'static> SignerClient<D> {
|
||||
let dispatcher = self.dispatcher.clone();
|
||||
let signer = self.signer.clone();
|
||||
|
||||
Box::new(signer.peek(&id).map(|confirmation| {
|
||||
let mut payload = confirmation.payload.clone();
|
||||
Box::new(signer.take(&id).map(|sender| {
|
||||
let mut payload = sender.request.payload.clone();
|
||||
// Modify payload
|
||||
if let ConfirmationPayload::SendTransaction(ref mut request) = payload {
|
||||
if let Some(sender) = modification.sender.clone() {
|
||||
if let Some(sender) = modification.sender {
|
||||
request.from = sender.into();
|
||||
// Altering sender should always reset the nonce.
|
||||
request.nonce = None;
|
||||
@@ -115,7 +115,9 @@ impl<D: Dispatcher + 'static> SignerClient<D> {
|
||||
Either::A(fut.into_future().then(move |result| {
|
||||
// Execute
|
||||
if let Ok(ref response) = result {
|
||||
signer.request_confirmed(id, Ok((*response).clone()));
|
||||
signer.request_confirmed(sender, Ok((*response).clone()));
|
||||
} else {
|
||||
signer.request_untouched(sender);
|
||||
}
|
||||
|
||||
result
|
||||
@@ -194,8 +196,9 @@ impl<D: Dispatcher + 'static> Signer for SignerClient<D> {
|
||||
fn confirm_request_raw(&self, id: U256, bytes: Bytes) -> Result<ConfirmationResponse> {
|
||||
let id = id.into();
|
||||
|
||||
self.signer.peek(&id).map(|confirmation| {
|
||||
let result = match confirmation.payload {
|
||||
self.signer.take(&id).map(|sender| {
|
||||
let payload = sender.request.payload.clone();
|
||||
let result = match payload {
|
||||
ConfirmationPayload::SendTransaction(request) => {
|
||||
Self::verify_transaction(bytes, request, |pending_transaction| {
|
||||
self.dispatcher.dispatch_transaction(pending_transaction)
|
||||
@@ -224,14 +227,16 @@ impl<D: Dispatcher + 'static> Signer for SignerClient<D> {
|
||||
},
|
||||
};
|
||||
if let Ok(ref response) = result {
|
||||
self.signer.request_confirmed(id, Ok(response.clone()));
|
||||
self.signer.request_confirmed(sender, Ok(response.clone()));
|
||||
} else {
|
||||
self.signer.request_untouched(sender);
|
||||
}
|
||||
result
|
||||
}).unwrap_or_else(|| Err(errors::invalid_params("Unknown RequestID", id)))
|
||||
}
|
||||
|
||||
fn reject_request(&self, id: U256) -> Result<bool> {
|
||||
let res = self.signer.request_rejected(id.into());
|
||||
let res = self.signer.take(&id.into()).map(|sender| self.signer.request_rejected(sender));
|
||||
Ok(res.is_some())
|
||||
}
|
||||
|
||||
|
||||
@@ -230,6 +230,18 @@ fn eth_get_block() {
|
||||
assert_eq!(tester.handler.handle_request_sync(req_block).unwrap(), res_block);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eth_get_block_by_hash() {
|
||||
let chain = extract_chain!("BlockchainTests/bcGasPricerTest/RPC_API_Test");
|
||||
let tester = EthTester::from_chain(&chain);
|
||||
|
||||
// We're looking for block number 4 from "RPC_API_Test_Frontier"
|
||||
let req_block = r#"{"method":"eth_getBlockByHash","params":["0x9c9bdab4cb53fd834e790b13545597f026494d42112e84c0aca9dd6bcc545295",false],"id":1,"jsonrpc":"2.0"}"#;
|
||||
|
||||
let res_block = r#"{"jsonrpc":"2.0","result":{"author":"0x8888f1f195afa192cfee860698584c030f4c9db1","difficulty":"0x200c0","extraData":"0x","gasLimit":"0x1dd8112","gasUsed":"0x5458","hash":"0x9c9bdab4cb53fd834e790b13545597f026494d42112e84c0aca9dd6bcc545295","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x8888f1f195afa192cfee860698584c030f4c9db1","mixHash":"0xaddea8d25bb0f955fa6c1d58d74ab8a3fec99d37943e2a261e3b12f97d6bff7c","nonce":"0x8e18bed16d5a88da","number":"0x4","parentHash":"0x2cbf4fc930c5b4c87598f43fc8eb26dccdab2f58a7d0d3ca92ec60a5444a330e","receiptsRoot":"0x7ed8026cf72ed0e98e6fd53ab406e51ffd34397d9da0052494ff41376fda7b5f","sealFields":["0xa0addea8d25bb0f955fa6c1d58d74ab8a3fec99d37943e2a261e3b12f97d6bff7c","0x888e18bed16d5a88da"],"sha3Uncles":"0x75cc08a7cb2cf8081446659fecb2633fb6b922d26edd59bd2272b1f5cae1c78b","size":"0x661","stateRoot":"0x68805721294e365020aca15ed56c360d9dc2cf03cbeff84c9b84b8aed023bfb5","timestamp":"0x59d662ff","totalDifficulty":"0xa0180","transactions":["0xb094b9dc356dbb8b256402c6d5709288066ad6a372c90c9c516f14277545fd58"],"transactionsRoot":"0x97a593d8d7e15b57f5c6bb25bc6c325463ef99f874bc08a78656c3ab5cb23262","uncles":["0xa1e9c9ecd2af999e0723aae1dc55dd9789ca618e0b34badcc8ac7d9a3dad3af2","0x81d429b6b6635214a2b0f976cc4b2ed49808140d6bede50129bc10d22ac9249e"]},"id":1}"#;
|
||||
assert_eq!(tester.handler.handle_request_sync(req_block).unwrap(), res_block);
|
||||
}
|
||||
|
||||
// a frontier-like test with an expanded gas limit and balance on known account.
|
||||
const TRANSACTION_COUNT_SPEC: &'static [u8] = br#"{
|
||||
"name": "Frontier (Test)",
|
||||
|
||||
@@ -110,7 +110,8 @@ fn should_add_sign_to_queue() {
|
||||
::std::thread::spawn(move || loop {
|
||||
if signer.requests().len() == 1 {
|
||||
// respond
|
||||
signer.request_confirmed(1.into(), Ok(ConfirmationResponse::Signature(0.into())));
|
||||
let sender = signer.take(&1.into()).unwrap();
|
||||
signer.request_confirmed(sender, Ok(ConfirmationResponse::Signature(0.into())));
|
||||
break
|
||||
}
|
||||
::std::thread::sleep(Duration::from_millis(100))
|
||||
@@ -188,7 +189,8 @@ fn should_check_status_of_request_when_its_resolved() {
|
||||
"id": 1
|
||||
}"#;
|
||||
tester.io.handle_request_sync(&request).expect("Sent");
|
||||
tester.signer.request_confirmed(1.into(), Ok(ConfirmationResponse::Signature(1.into())));
|
||||
let sender = tester.signer.take(&1.into()).unwrap();
|
||||
tester.signer.request_confirmed(sender, Ok(ConfirmationResponse::Signature(1.into())));
|
||||
|
||||
// This is not ideal, but we need to give futures some time to be executed, and they need to run in a separate thread
|
||||
thread::sleep(Duration::from_millis(20));
|
||||
@@ -259,7 +261,8 @@ fn should_add_transaction_to_queue() {
|
||||
::std::thread::spawn(move || loop {
|
||||
if signer.requests().len() == 1 {
|
||||
// respond
|
||||
signer.request_confirmed(1.into(), Ok(ConfirmationResponse::SendTransaction(0.into())));
|
||||
let sender = signer.take(&1.into()).unwrap();
|
||||
signer.request_confirmed(sender, Ok(ConfirmationResponse::SendTransaction(0.into())));
|
||||
break
|
||||
}
|
||||
::std::thread::sleep(Duration::from_millis(100))
|
||||
@@ -335,7 +338,8 @@ fn should_add_sign_transaction_to_the_queue() {
|
||||
::std::thread::spawn(move || loop {
|
||||
if signer.requests().len() == 1 {
|
||||
// respond
|
||||
signer.request_confirmed(1.into(), Ok(ConfirmationResponse::SignTransaction(
|
||||
let sender = signer.take(&1.into()).unwrap();
|
||||
signer.request_confirmed(sender, Ok(ConfirmationResponse::SignTransaction(
|
||||
RichRawTransaction::from_signed(t.into(), 0x0, u64::max_value())
|
||||
)));
|
||||
break
|
||||
@@ -442,7 +446,8 @@ fn should_add_decryption_to_the_queue() {
|
||||
::std::thread::spawn(move || loop {
|
||||
if signer.requests().len() == 1 {
|
||||
// respond
|
||||
signer.request_confirmed(1.into(), Ok(ConfirmationResponse::Decrypt(vec![0x1, 0x2].into())));
|
||||
let sender = signer.take(&1.into()).unwrap();
|
||||
signer.request_confirmed(sender, Ok(ConfirmationResponse::Decrypt(vec![0x1, 0x2].into())));
|
||||
break
|
||||
}
|
||||
::std::thread::sleep(Duration::from_millis(10))
|
||||
|
||||
@@ -55,7 +55,13 @@ macro_rules! impl_uint {
|
||||
|
||||
impl fmt::LowerHex for $name {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:#x}", self.0)
|
||||
// TODO: remove this once updated to new version of primitives
|
||||
// including https://github.com/paritytech/primitives/pull/33
|
||||
// replace with `::core::fmt::LowerHex::fmt(self.0, f)`
|
||||
if f.alternate() {
|
||||
write!(f, "0x");
|
||||
}
|
||||
write!(f, "{:x}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,19 +108,19 @@ impl_uint!(U64, u64, 1);
|
||||
|
||||
impl serde::Serialize for U128 {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
|
||||
serializer.serialize_str(&format!("0x{:x}", self.0))
|
||||
serializer.serialize_str(&format!("{:#x}", self))
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::Serialize for U256 {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
|
||||
serializer.serialize_str(&format!("0x{:x}", self.0))
|
||||
serializer.serialize_str(&format!("{:#x}", self))
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::Serialize for U64 {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
|
||||
serializer.serialize_str(&format!("0x{:x}", self.0))
|
||||
serializer.serialize_str(&format!("{:#x}", self))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
cd docker/hub
|
||||
DOCKER_BUILD_TAG=$1
|
||||
echo "Docker build tag: " $DOCKER_BUILD_TAG
|
||||
docker build --build-arg BUILD_TAG=$DOCKER_BUILD_TAG --no-cache=true --tag parity/parity:$DOCKER_BUILD_TAG .
|
||||
if [[ "$DOCKER_BUILD_TAG" = "latest" ]]; then
|
||||
docker build --build-arg BUILD_TAG="master" --no-cache=true --tag parity/parity:$DOCKER_BUILD_TAG .
|
||||
else
|
||||
docker build --build-arg BUILD_TAG=$DOCKER_BUILD_TAG --no-cache=true --tag parity/parity:$DOCKER_BUILD_TAG .
|
||||
fi
|
||||
docker run -it parity/parity:$DOCKER_BUILD_TAG -v
|
||||
docker push parity/parity:$DOCKER_BUILD_TAG
|
||||
|
||||
@@ -22,9 +22,8 @@ echo "Parity version: " $VER
|
||||
echo "Branch: " $CI_BUILD_REF_NAME
|
||||
echo "--------------------"
|
||||
|
||||
# NOTE for md5 and sha256 we want to display filename as well
|
||||
# NOTE for sha256 we want to display filename as well
|
||||
# hence we use --* instead of -p *
|
||||
MD5_BIN="rhash --md5"
|
||||
SHA256_BIN="rhash --sha256"
|
||||
|
||||
set_env () {
|
||||
@@ -74,20 +73,15 @@ calculate_checksums () {
|
||||
echo "Checksum calculation:"
|
||||
rhash --version
|
||||
|
||||
rm -rf *.md5
|
||||
rm -rf *.sha256
|
||||
|
||||
BIN="target/$PLATFORM/release/parity$S3WIN"
|
||||
export SHA3="$($BIN tools hash $BIN)"
|
||||
|
||||
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 () {
|
||||
@@ -123,7 +117,6 @@ make_deb () {
|
||||
cp target/$PLATFORM/release/ethstore deb/usr/bin/ethstore
|
||||
cp target/$PLATFORM/release/ethkey deb/usr/bin/ethkey
|
||||
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 () {
|
||||
@@ -137,7 +130,6 @@ make_rpm () {
|
||||
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"_"$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 () {
|
||||
@@ -152,11 +144,13 @@ make_pkg () {
|
||||
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"_"$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"
|
||||
./sign.cmd $keyfile $certpass "target/$PLATFORM/release/parity-evm.exe"
|
||||
./sign.cmd $keyfile $certpass "target/$PLATFORM/release/ethstore.exe"
|
||||
./sign.cmd $keyfile $certpass "target/$PLATFORM/release/ethkey.exe"
|
||||
}
|
||||
make_exe () {
|
||||
./msbuild.cmd
|
||||
@@ -168,7 +162,6 @@ make_exe () {
|
||||
cd ..
|
||||
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 () {
|
||||
@@ -183,25 +176,21 @@ push_binaries () {
|
||||
fi
|
||||
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/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 parity$S3WIN.sha256 parity-evm$S3WIN.sha256 ethstore$S3WIN.sha256 ethkey$S3WIN.sha256
|
||||
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.sha256 parity-evm$S3WIN.sha256 ethstore$S3WIN.sha256 ethkey$S3WIN.sha256
|
||||
}
|
||||
|
||||
updater_push_release () {
|
||||
@@ -309,11 +298,12 @@ case $BUILD_PLATFORM in
|
||||
x86_64-unknown-snap-gnu)
|
||||
ARC="amd64"
|
||||
EXT="snap"
|
||||
apt update
|
||||
apt install -y expect zip rhash
|
||||
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.11* ]];
|
||||
if [[ "$CI_BUILD_REF_NAME" = "stable" || "$CI_BUILD_REF_NAME" = "beta" || "$VER" == *1.10* || "$VER" == *1.11* ]];
|
||||
then
|
||||
sed -i -e 's/grade: devel/grade: stable/' snap/snapcraft.yaml;
|
||||
fi
|
||||
@@ -331,11 +321,10 @@ case $BUILD_PLATFORM in
|
||||
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"
|
||||
zip -r parity.zip "parity_"$VER"_amd64.snap" "parity_"$VER"_amd64.snap.sha256"
|
||||
;;
|
||||
x86_64-pc-windows-msvc)
|
||||
set_env_win
|
||||
|
||||
@@ -7,8 +7,8 @@ if [[ "$CI_COMMIT_REF_NAME" = "beta" || "$CI_COMMIT_REF_NAME" = "stable" ]]; the
|
||||
else
|
||||
export GIT_COMPARE=master;
|
||||
fi
|
||||
export RUST_FILES_MODIFIED="$(git --no-pager diff --name-only $GIT_COMPARE...$CI_COMMIT_SHA | grep -v -e ^\\. -e ^LICENSE -e ^README.md -e ^test.sh -e ^windows/ -e ^scripts/ -e ^mac/ -e ^nsis/ | wc -l)"
|
||||
echo "RUST_FILES_MODIFIED: $RUST_FILES_MODIFIED"
|
||||
git fetch -a
|
||||
export RUST_FILES_MODIFIED="$(git --no-pager diff --name-only $GIT_COMPARE...$CI_COMMIT_SHA | grep -v -e ^\\. -e ^LICENSE -e ^README.md -e ^test.sh -e ^windows/ -e ^scripts/ -e ^mac/ -e ^nsis/ -e ^docs/ | wc -l)"
|
||||
echo "RUST_FILES_MODIFIED: $RUST_FILES_MODIFIED"
|
||||
TEST_SWITCH=$1
|
||||
rust_test () {
|
||||
|
||||
@@ -30,6 +30,8 @@ parts:
|
||||
parity:
|
||||
source: .
|
||||
plugin: rust
|
||||
# rust-channel: stable # @TODO enable after https://bugs.launchpad.net/snapcraft/+bug/1778530
|
||||
rust-revision: 1.26.2 # @TODO remove after https://bugs.launchpad.net/snapcraft/+bug/1778530
|
||||
build-attributes: [no-system-libraries]
|
||||
build-packages: [g++, libudev-dev, libssl-dev, make, pkg-config]
|
||||
stage-packages: [libc6, libssl1.0.0, libudev1, libstdc++6]
|
||||
|
||||
@@ -1579,7 +1579,7 @@ impl ChainSync {
|
||||
let max_count = cmp::min(MAX_HEADERS_TO_SEND, max_headers);
|
||||
let mut count = 0;
|
||||
let mut data = Bytes::new();
|
||||
let inc = (skip + 1) as BlockNumber;
|
||||
let inc = skip.saturating_add(1) as BlockNumber;
|
||||
let overlay = io.chain_overlay().read();
|
||||
|
||||
while number <= last && count < max_count {
|
||||
@@ -1598,10 +1598,10 @@ impl ChainSync {
|
||||
if number <= inc || number == 0 {
|
||||
break;
|
||||
}
|
||||
number -= inc;
|
||||
number = number.saturating_sub(inc);
|
||||
}
|
||||
else {
|
||||
number += inc;
|
||||
number = number.saturating_add(inc);
|
||||
}
|
||||
}
|
||||
let mut rlp = RlpStream::new_list(count as usize);
|
||||
|
||||
@@ -56,7 +56,7 @@ enum RemoveFrom {
|
||||
/// the removals actually take effect.
|
||||
///
|
||||
/// journal format:
|
||||
/// ```
|
||||
/// ```text
|
||||
/// [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ]
|
||||
/// [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ]
|
||||
/// [era, n] => [ ... ]
|
||||
@@ -75,7 +75,7 @@ enum RemoveFrom {
|
||||
/// which includes an original key, if any.
|
||||
///
|
||||
/// The semantics of the `counter` are:
|
||||
/// ```
|
||||
/// ```text
|
||||
/// insert key k:
|
||||
/// counter already contains k: count += 1
|
||||
/// counter doesn't contain k:
|
||||
@@ -91,7 +91,7 @@ enum RemoveFrom {
|
||||
///
|
||||
/// Practically, this means that for each commit block turning from recent to ancient we do the
|
||||
/// following:
|
||||
/// ```
|
||||
/// ```text
|
||||
/// is_canonical:
|
||||
/// inserts: Ignored (left alone in the backing database).
|
||||
/// deletes: Enacted; however, recent history queue is checked for ongoing references. This is
|
||||
|
||||
@@ -39,7 +39,7 @@ use bytes::Bytes;
|
||||
/// the removals actually take effect.
|
||||
///
|
||||
/// journal format:
|
||||
/// ```
|
||||
/// ```text
|
||||
/// [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ]
|
||||
/// [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ]
|
||||
/// [era, n] => [ ... ]
|
||||
|
||||
@@ -227,10 +227,13 @@ pub struct NetworkContext<'s> {
|
||||
|
||||
impl<'s> NetworkContext<'s> {
|
||||
/// Create a new network IO access point. Takes references to all the data that can be updated within the IO handler.
|
||||
fn new(io: &'s IoContext<NetworkIoMessage>,
|
||||
fn new(
|
||||
io: &'s IoContext<NetworkIoMessage>,
|
||||
protocol: ProtocolId,
|
||||
session: Option<SharedSession>, sessions: Arc<RwLock<Slab<SharedSession>>>,
|
||||
reserved_peers: &'s HashSet<NodeId>) -> NetworkContext<'s> {
|
||||
session: Option<SharedSession>,
|
||||
sessions: Arc<RwLock<Slab<SharedSession>>>,
|
||||
reserved_peers: &'s HashSet<NodeId>,
|
||||
) -> NetworkContext<'s> {
|
||||
let id = session.as_ref().map(|s| s.lock().token());
|
||||
NetworkContext {
|
||||
io: io,
|
||||
@@ -722,10 +725,8 @@ impl Host {
|
||||
let address = {
|
||||
let mut nodes = self.nodes.write();
|
||||
if let Some(node) = nodes.get_mut(id) {
|
||||
node.attempts += 1;
|
||||
node.endpoint.address
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
debug!(target: "network", "Connection to expired node aborted");
|
||||
return;
|
||||
}
|
||||
@@ -737,6 +738,7 @@ impl Host {
|
||||
},
|
||||
Err(e) => {
|
||||
debug!(target: "network", "{}: Can't connect to address {:?}: {:?}", id, address, e);
|
||||
self.nodes.write().note_failure(&id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -822,12 +824,17 @@ impl Host {
|
||||
Err(e) => {
|
||||
let s = session.lock();
|
||||
trace!(target: "network", "Session read error: {}:{:?} ({:?}) {:?}", token, s.id(), s.remote_addr(), e);
|
||||
if let ErrorKind::Disconnect(DisconnectReason::IncompatibleProtocol) = *e.kind() {
|
||||
if let Some(id) = s.id() {
|
||||
if !self.reserved_nodes.read().contains(id) {
|
||||
self.nodes.write().mark_as_useless(id);
|
||||
match *e.kind() {
|
||||
ErrorKind::Disconnect(DisconnectReason::IncompatibleProtocol) | ErrorKind::Disconnect(DisconnectReason::UselessPeer) => {
|
||||
if let Some(id) = s.id() {
|
||||
if !self.reserved_nodes.read().contains(id) {
|
||||
let mut nodes = self.nodes.write();
|
||||
nodes.note_failure(&id);
|
||||
nodes.mark_as_useless(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
kill = true;
|
||||
break;
|
||||
@@ -891,6 +898,10 @@ impl Host {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note connection success
|
||||
self.nodes.write().note_success(&id);
|
||||
|
||||
for (p, _) in self.handlers.read().iter() {
|
||||
if s.have_capability(*p) {
|
||||
ready_data.push(*p);
|
||||
@@ -1162,7 +1173,9 @@ impl IoHandler<NetworkIoMessage> for Host {
|
||||
if let Some(session) = session {
|
||||
session.lock().disconnect(io, DisconnectReason::DisconnectRequested);
|
||||
if let Some(id) = session.lock().id() {
|
||||
self.nodes.write().mark_as_useless(id)
|
||||
let mut nodes = self.nodes.write();
|
||||
nodes.note_failure(&id);
|
||||
nodes.mark_as_useless(id);
|
||||
}
|
||||
}
|
||||
trace!(target: "network", "Disabling peer {}", peer);
|
||||
|
||||
@@ -21,6 +21,8 @@ use std::net::{SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, Ipv4Addr,
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::{fs, mem, slice};
|
||||
use std::time::{self, Duration, SystemTime};
|
||||
use rand::{self, Rng};
|
||||
use ethereum_types::H512;
|
||||
use rlp::*;
|
||||
use error::{Error, ErrorKind};
|
||||
@@ -128,40 +130,64 @@ impl FromStr for NodeEndpoint {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Copy, Clone)]
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
pub enum PeerType {
|
||||
_Required,
|
||||
Optional
|
||||
}
|
||||
|
||||
/// A type for representing an interaction (contact) with a node at a given time
|
||||
/// that was either a success or a failure.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum NodeContact {
|
||||
Success(SystemTime),
|
||||
Failure(SystemTime),
|
||||
}
|
||||
|
||||
impl NodeContact {
|
||||
fn success() -> NodeContact {
|
||||
NodeContact::Success(SystemTime::now())
|
||||
}
|
||||
|
||||
fn failure() -> NodeContact {
|
||||
NodeContact::Failure(SystemTime::now())
|
||||
}
|
||||
|
||||
fn time(&self) -> SystemTime {
|
||||
match *self {
|
||||
NodeContact::Success(t) | NodeContact::Failure(t) => t
|
||||
}
|
||||
}
|
||||
|
||||
/// Filters and old contact, returning `None` if it happened longer than a
|
||||
/// week ago.
|
||||
fn recent(&self) -> Option<&NodeContact> {
|
||||
let t = self.time();
|
||||
if let Ok(d) = t.elapsed() {
|
||||
if d < Duration::from_secs(60 * 60 * 24 * 7) {
|
||||
return Some(self);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Node {
|
||||
pub id: NodeId,
|
||||
pub endpoint: NodeEndpoint,
|
||||
pub peer_type: PeerType,
|
||||
pub attempts: u32,
|
||||
pub failures: u32,
|
||||
pub last_contact: Option<NodeContact>,
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
last_contact: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -191,8 +217,7 @@ impl FromStr for Node {
|
||||
id: id,
|
||||
endpoint: endpoint,
|
||||
peer_type: PeerType::Optional,
|
||||
attempts: 0,
|
||||
failures: 0,
|
||||
last_contact: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -231,28 +256,61 @@ impl NodeTable {
|
||||
|
||||
/// Add a node to table
|
||||
pub fn add_node(&mut self, mut node: Node) {
|
||||
// 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;
|
||||
|
||||
// preserve node last_contact
|
||||
node.last_contact = self.nodes.get(&node.id).and_then(|n| n.last_contact);
|
||||
self.nodes.insert(node.id.clone(), node);
|
||||
}
|
||||
|
||||
/// Returns a list of ordered nodes according to their most recent contact
|
||||
/// and filtering useless nodes. The algorithm for creating the sorted nodes
|
||||
/// is:
|
||||
/// - Contacts that aren't recent (older than 1 week) are discarded
|
||||
/// - (1) Nodes with a successful contact are ordered (most recent success first)
|
||||
/// - (2) Nodes with unknown contact (older than 1 week or new nodes) are randomly shuffled
|
||||
/// - (3) Nodes with a failed contact are ordered (oldest failure first)
|
||||
/// - The final result is the concatenation of (1), (2) and (3)
|
||||
fn ordered_entries(&self) -> Vec<&Node> {
|
||||
let mut refs: Vec<&Node> = self.nodes.values()
|
||||
.filter(|n| !self.useless_nodes.contains(&n.id))
|
||||
.collect();
|
||||
let mut success = Vec::new();
|
||||
let mut failures = Vec::new();
|
||||
let mut unknown = Vec::new();
|
||||
|
||||
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
|
||||
let nodes = self.nodes.values()
|
||||
.filter(|n| !self.useless_nodes.contains(&n.id));
|
||||
|
||||
for node in nodes {
|
||||
// discard contact points older that aren't recent
|
||||
match node.last_contact.as_ref().and_then(|c| c.recent()) {
|
||||
Some(&NodeContact::Success(_)) => {
|
||||
success.push(node);
|
||||
},
|
||||
Some(&NodeContact::Failure(_)) => {
|
||||
failures.push(node);
|
||||
},
|
||||
None => {
|
||||
unknown.push(node);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
success.sort_by(|a, b| {
|
||||
let a = a.last_contact.expect("vector only contains values with defined last_contact; qed");
|
||||
let b = b.last_contact.expect("vector only contains values with defined last_contact; qed");
|
||||
// inverse ordering, most recent successes come first
|
||||
b.time().cmp(&a.time())
|
||||
});
|
||||
|
||||
refs
|
||||
failures.sort_by(|a, b| {
|
||||
let a = a.last_contact.expect("vector only contains values with defined last_contact; qed");
|
||||
let b = b.last_contact.expect("vector only contains values with defined last_contact; qed");
|
||||
// normal ordering, most distant failures come first
|
||||
a.time().cmp(&b.time())
|
||||
});
|
||||
|
||||
rand::thread_rng().shuffle(&mut unknown);
|
||||
|
||||
success.append(&mut unknown);
|
||||
success.append(&mut failures);
|
||||
success
|
||||
}
|
||||
|
||||
/// Returns node ids sorted by failure percentage, for nodes with the same failure percentage the absolute number of
|
||||
@@ -296,10 +354,17 @@ impl NodeTable {
|
||||
}
|
||||
}
|
||||
|
||||
/// Increase failure counte for a node
|
||||
/// Set last contact as failure for a node
|
||||
pub fn note_failure(&mut self, id: &NodeId) {
|
||||
if let Some(node) = self.nodes.get_mut(id) {
|
||||
node.failures += 1;
|
||||
node.last_contact = Some(NodeContact::failure());
|
||||
}
|
||||
}
|
||||
|
||||
/// Set last contact as success for a node
|
||||
pub fn note_success(&mut self, id: &NodeId) {
|
||||
if let Some(node) = self.nodes.get_mut(id) {
|
||||
node.last_contact = Some(NodeContact::success());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -396,19 +461,38 @@ mod json {
|
||||
pub nodes: Vec<Node>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub enum NodeContact {
|
||||
#[serde(rename = "success")]
|
||||
Success(u64),
|
||||
#[serde(rename = "failure")]
|
||||
Failure(u64),
|
||||
}
|
||||
|
||||
impl NodeContact {
|
||||
pub fn into_node_contact(self) -> super::NodeContact {
|
||||
match self {
|
||||
NodeContact::Success(s) => super::NodeContact::Success(
|
||||
time::UNIX_EPOCH + Duration::from_secs(s)
|
||||
),
|
||||
NodeContact::Failure(s) => super::NodeContact::Failure(
|
||||
time::UNIX_EPOCH + Duration::from_secs(s)
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Node {
|
||||
pub url: String,
|
||||
pub attempts: u32,
|
||||
pub failures: u32,
|
||||
pub last_contact: Option<NodeContact>,
|
||||
}
|
||||
|
||||
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;
|
||||
node.last_contact = self.last_contact.map(|c| c.into_node_contact());
|
||||
Some(node)
|
||||
},
|
||||
_ => None,
|
||||
@@ -418,10 +502,18 @@ mod json {
|
||||
|
||||
impl<'a> From<&'a super::Node> for Node {
|
||||
fn from(node: &'a super::Node) -> Self {
|
||||
let last_contact = node.last_contact.and_then(|c| {
|
||||
match c {
|
||||
super::NodeContact::Success(t) =>
|
||||
t.duration_since(time::UNIX_EPOCH).ok().map(|d| NodeContact::Success(d.as_secs())),
|
||||
super::NodeContact::Failure(t) =>
|
||||
t.duration_since(time::UNIX_EPOCH).ok().map(|d| NodeContact::Failure(d.as_secs())),
|
||||
}
|
||||
});
|
||||
|
||||
Node {
|
||||
url: format!("{}", node),
|
||||
attempts: node.attempts,
|
||||
failures: node.failures,
|
||||
last_contact
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -464,42 +556,54 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn table_failure_percentage_order() {
|
||||
fn table_last_contact_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 node5 = Node::from_str("enode://e979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap();
|
||||
let node6 = Node::from_str("enode://f979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@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 id5 = H512::from_str("e979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
|
||||
let id6 = H512::from_str("f979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
|
||||
let mut table = NodeTable::new(None);
|
||||
|
||||
table.add_node(node1);
|
||||
table.add_node(node2);
|
||||
table.add_node(node3);
|
||||
table.add_node(node4);
|
||||
table.add_node(node5);
|
||||
table.add_node(node6);
|
||||
|
||||
// node 1 - failure percentage 100%
|
||||
table.get_mut(&id1).unwrap().attempts = 2;
|
||||
// failures - nodes 1 & 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;
|
||||
// success - nodes 3 & 4
|
||||
table.note_success(&id3);
|
||||
table.note_success(&id4);
|
||||
|
||||
// node4 - failure percentage 50% (default when no attempts)
|
||||
// success - node 5 (old contact)
|
||||
table.get_mut(&id5).unwrap().last_contact = Some(NodeContact::Success(time::UNIX_EPOCH));
|
||||
|
||||
// unknown - node 6
|
||||
|
||||
let r = table.nodes(IpFilter::default());
|
||||
|
||||
assert_eq!(r[0][..], id3[..]);
|
||||
assert_eq!(r[1][..], id2[..]);
|
||||
assert_eq!(r[2][..], id4[..]);
|
||||
assert_eq!(r[3][..], id1[..]);
|
||||
assert_eq!(r[0][..], id4[..]); // most recent success
|
||||
assert_eq!(r[1][..], id3[..]);
|
||||
|
||||
// unknown (old contacts and new nodes), randomly shuffled
|
||||
assert!(
|
||||
r[2][..] == id5[..] && r[3][..] == id6[..] ||
|
||||
r[2][..] == id6[..] && r[3][..] == id5[..]
|
||||
);
|
||||
|
||||
assert_eq!(r[4][..], id1[..]); // oldest failure
|
||||
assert_eq!(r[5][..], id2[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -507,23 +611,27 @@ mod tests {
|
||||
let tempdir = TempDir::new("").unwrap();
|
||||
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 id1 = H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
|
||||
let id2 = H512::from_str("b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
|
||||
let id3 = H512::from_str("c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
|
||||
|
||||
{
|
||||
let mut table = NodeTable::new(Some(tempdir.path().to_str().unwrap().to_owned()));
|
||||
table.add_node(node1);
|
||||
table.add_node(node2);
|
||||
table.add_node(node3);
|
||||
|
||||
table.get_mut(&id1).unwrap().attempts = 1;
|
||||
table.get_mut(&id2).unwrap().attempts = 1;
|
||||
table.note_failure(&id2);
|
||||
table.note_success(&id2);
|
||||
table.note_failure(&id3);
|
||||
}
|
||||
|
||||
{
|
||||
let table = NodeTable::new(Some(tempdir.path().to_str().unwrap().to_owned()));
|
||||
let r = table.nodes(IpFilter::default());
|
||||
assert_eq!(r[0][..], id1[..]);
|
||||
assert_eq!(r[1][..], id2[..]);
|
||||
assert_eq!(r[0][..], id2[..]); // latest success
|
||||
assert_eq!(r[1][..], id1[..]); // unknown
|
||||
assert_eq!(r[2][..], id3[..]); // oldest failure
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[package]
|
||||
name = "parity-version"
|
||||
# NOTE: this value is used for Parity version string (via env CARGO_PKG_VERSION)
|
||||
version = "1.10.3"
|
||||
version = "1.10.9"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
build = "build.rs"
|
||||
|
||||
@@ -12,14 +12,13 @@ build = "build.rs"
|
||||
# Used by auto-updater and for Parity version string.
|
||||
track = "stable"
|
||||
|
||||
# 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 = 6600000
|
||||
# Network specific settings, used ONLY by auto-updater.
|
||||
# Latest supported fork blocks.
|
||||
# Indicates a critical release in this track (i.e. consensus issue).
|
||||
[package.metadata.networks]
|
||||
foundation = { forkBlock = 4370000, critical = false }
|
||||
ropsten = { forkBlock = 10, critical = false }
|
||||
kovan = { forkBlock = 6600000, critical = false }
|
||||
|
||||
[dependencies]
|
||||
ethcore-bytes = { path = "../bytes" }
|
||||
|
||||
Reference in New Issue
Block a user