Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3fd58bdcbd | ||
|
|
ecbafb2390 | ||
|
|
adabd8198c | ||
|
|
c2487cfe07 | ||
|
|
e0141f8324 | ||
|
|
b52ac20660 | ||
|
|
3c85f29f11 |
140
.gitlab-ci.yml
140
.gitlab-ci.yml
@@ -4,11 +4,13 @@ stages:
|
||||
- publish
|
||||
- optional
|
||||
|
||||
image: parity/rust-parity-ethereum-build:xenial
|
||||
image: parity/parity-ci-linux:latest
|
||||
variables:
|
||||
GIT_STRATEGY: fetch
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
CI_SERVER_NAME: "GitLab CI"
|
||||
CARGO_HOME: "/ci-cache/${CI_PROJECT_NAME}/cargo/${CI_JOB_NAME}"
|
||||
SCCACHE_DIR: "/ci-cache/${CI_PROJECT_NAME}/sccache"
|
||||
CARGO_TARGET: x86_64-unknown-linux-gnu
|
||||
|
||||
.no_git: &no_git # disable git strategy
|
||||
@@ -30,41 +32,72 @@ variables:
|
||||
expire_in: 1 mos
|
||||
paths:
|
||||
- artifacts/
|
||||
- tools/
|
||||
|
||||
.docker-cache-status: &docker-cache-status
|
||||
variables:
|
||||
CARGO_HOME: "/ci-cache/parity-ethereum/cargo/${CI_JOB_NAME}"
|
||||
dependencies: []
|
||||
before_script:
|
||||
- SCCACHE_ERROR_LOG=/builds/parity/parity-ethereum/sccache_error.log RUST_LOG=sccache::server=debug sccache --start-server
|
||||
- rustup show
|
||||
- cargo --version
|
||||
- SCCACHE_ERROR_LOG=/builds/parity/parity-ethereum/sccache_debug.log
|
||||
RUST_LOG=sccache=debug
|
||||
sccache --start-server
|
||||
- sccache -s
|
||||
after_script:
|
||||
- echo "All crate-types:"
|
||||
- grep 'parse_arguments.*--crate-type' sccache_error.log | sed -re 's/.*"--crate-type", "([^"]+)".*/\1/' | sort | uniq -c
|
||||
- echo "Non-cacheable reasons:"
|
||||
- grep CannotCache sccache_error.log | sed -re 's/.*CannotCache\((.+)\).*/\1/' | sort | uniq -c
|
||||
# sccache debug info
|
||||
- if test -e sccache_debug.log;
|
||||
then
|
||||
echo "_____All crate-types:_____";
|
||||
grep 'parse_arguments.*--crate-type' sccache_debug.log | sed -re 's/.*"--crate-type", "([^"]+)".*/\1/' | sort | uniq -c;
|
||||
echo "_____Non-cacheable reasons:_____";
|
||||
grep CannotCache sccache_debug.log | sed -re 's/.*CannotCache\((.+)\).*/\1/' | sort | uniq -c;
|
||||
else
|
||||
echo "_____No logs from sccache_____";
|
||||
exit 0;
|
||||
fi
|
||||
tags:
|
||||
- linux-docker
|
||||
|
||||
.build-on-linux: &build-on-linux
|
||||
stage: build
|
||||
<<: *docker-cache-status
|
||||
<<: *collect_artifacts
|
||||
script:
|
||||
- scripts/gitlab/build-linux.sh
|
||||
- sccache -s
|
||||
after_script:
|
||||
- mkdir -p tools
|
||||
- cp -r scripts/docker/hub/* ./tools
|
||||
- cp scripts/gitlab/publish-snap.sh ./tools
|
||||
- cp scripts/gitlab/publish-onchain.sh ./tools
|
||||
- cp scripts/gitlab/safe-curl.sh ./tools
|
||||
- echo v"$(sed -r -n '1,/^version/s/^version\s*=\s*"([^"]+)".*$/\1/p' Cargo.toml)" |
|
||||
tee ./tools/VERSION
|
||||
- echo "$(sed -r -n '1,/^track/s/^track\s*=\s*"([^"]+)".*$/\1/p' ./util/version/Cargo.toml)" |
|
||||
tee ./tools/TRACK
|
||||
|
||||
|
||||
cargo-check 0 3:
|
||||
stage: test
|
||||
<<: *docker-cache-status
|
||||
script:
|
||||
- time cargo check --target $CARGO_TARGET --locked --no-default-features
|
||||
- time cargo check --target $CARGO_TARGET --locked --no-default-features --verbose --color=always
|
||||
- sccache -s
|
||||
|
||||
cargo-check 1 3:
|
||||
stage: test
|
||||
<<: *docker-cache-status
|
||||
script:
|
||||
- time cargo check --target $CARGO_TARGET --locked --manifest-path util/io/Cargo.toml --no-default-features
|
||||
- time cargo check --target $CARGO_TARGET --locked --manifest-path util/io/Cargo.toml --no-default-features --verbose --color=always
|
||||
- sccache -s
|
||||
|
||||
cargo-check 2 3:
|
||||
stage: test
|
||||
<<: *docker-cache-status
|
||||
script:
|
||||
- time cargo check --target $CARGO_TARGET --locked --manifest-path util/io/Cargo.toml --features "mio"
|
||||
- time cargo check --target $CARGO_TARGET --locked --manifest-path util/io/Cargo.toml --features "mio" --verbose --color=always
|
||||
- sccache -s
|
||||
|
||||
cargo-audit:
|
||||
@@ -72,7 +105,7 @@ cargo-audit:
|
||||
<<: *docker-cache-status
|
||||
script:
|
||||
- cargo audit
|
||||
- sccache -s
|
||||
allow_failure: true # failed cargo audit shouldn't prevent a PR from being merged
|
||||
|
||||
validate-chainspecs:
|
||||
stage: test
|
||||
@@ -92,55 +125,64 @@ test-linux:
|
||||
stage: build
|
||||
<<: *docker-cache-status
|
||||
script:
|
||||
- ./scripts/gitlab/test-linux.sh
|
||||
- ./scripts/gitlab/test-linux.sh stable
|
||||
- sccache -s
|
||||
|
||||
build-android:
|
||||
stage: build
|
||||
image: parity/rust-parity-ethereum-android-build:stretch
|
||||
variables:
|
||||
CARGO_TARGET: armv7-linux-androideabi
|
||||
<<: *docker-cache-status
|
||||
<<: *collect_artifacts
|
||||
script:
|
||||
- scripts/gitlab/build-linux.sh
|
||||
tags:
|
||||
- linux-docker
|
||||
|
||||
build-linux: &build-linux
|
||||
test-linux-beta:
|
||||
stage: build
|
||||
only: *releaseable_branches
|
||||
<<: *docker-cache-status
|
||||
<<: *collect_artifacts
|
||||
script:
|
||||
- scripts/gitlab/build-linux.sh
|
||||
- ./scripts/gitlab/test-linux.sh beta
|
||||
- sccache -s
|
||||
|
||||
test-linux-nightly:
|
||||
stage: build
|
||||
only: *releaseable_branches
|
||||
<<: *docker-cache-status
|
||||
script:
|
||||
- ./scripts/gitlab/test-linux.sh nightly
|
||||
- sccache -s
|
||||
allow_failure: true
|
||||
|
||||
build-android:
|
||||
<<: *build-on-linux
|
||||
image: parity/rust-parity-ethereum-android-build:stretch
|
||||
variables:
|
||||
CARGO_TARGET: armv7-linux-androideabi
|
||||
|
||||
build-linux:
|
||||
<<: *build-on-linux
|
||||
only: *releaseable_branches
|
||||
|
||||
build-linux-i386:
|
||||
<<: *build-linux
|
||||
<<: *build-on-linux
|
||||
only: *releaseable_branches
|
||||
image: parity/rust-parity-ethereum-build:i386
|
||||
variables:
|
||||
CARGO_TARGET: i686-unknown-linux-gnu
|
||||
|
||||
build-linux-arm64:
|
||||
<<: *build-linux
|
||||
<<: *build-on-linux
|
||||
only: *releaseable_branches
|
||||
image: parity/rust-parity-ethereum-build:arm64
|
||||
variables:
|
||||
CARGO_TARGET: aarch64-unknown-linux-gnu
|
||||
|
||||
build-linux-armhf:
|
||||
<<: *build-linux
|
||||
<<: *build-on-linux
|
||||
only: *releaseable_branches
|
||||
image: parity/rust-parity-ethereum-build:armhf
|
||||
variables:
|
||||
CARGO_TARGET: armv7-unknown-linux-gnueabihf
|
||||
|
||||
build-darwin:
|
||||
stage: build
|
||||
only: *releaseable_branches
|
||||
<<: *collect_artifacts
|
||||
only: *releaseable_branches
|
||||
variables:
|
||||
CARGO_TARGET: x86_64-apple-darwin
|
||||
CARGO_HOME: "${CI_PROJECT_DIR}/.cargo"
|
||||
CARGO_HOME: "${CI_PROJECT_DIR}/.cargo"
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
script:
|
||||
@@ -163,19 +205,35 @@ build-windows:
|
||||
|
||||
publish-docker:
|
||||
stage: publish
|
||||
<<: *no_git
|
||||
only: *releaseable_branches
|
||||
cache: {}
|
||||
except:
|
||||
variables:
|
||||
- $SCHEDULE_TAG == "nightly"
|
||||
dependencies:
|
||||
- build-linux
|
||||
tags:
|
||||
- shell
|
||||
environment:
|
||||
name: parity-build
|
||||
cache: {}
|
||||
image: docker:stable
|
||||
services:
|
||||
- docker:dind
|
||||
variables:
|
||||
DOCKER_HOST: tcp://localhost:2375
|
||||
DOCKER_DRIVER: overlay2
|
||||
GIT_STRATEGY: none
|
||||
# DOCKERFILE: tools/Dockerfile
|
||||
# CONTAINER_IMAGE: parity/parity
|
||||
script:
|
||||
- scripts/gitlab/publish-docker.sh parity
|
||||
# we stopped pushing nightlies to dockerhub, will push to own registry prb.
|
||||
- ./tools/publish-docker.sh
|
||||
tags:
|
||||
- kubernetes-parity-build
|
||||
|
||||
publish-snap: &publish-snap
|
||||
stage: publish
|
||||
<<: *no_git
|
||||
only: *releaseable_branches
|
||||
<<: *collect_artifacts
|
||||
image: snapcore/snapcraft
|
||||
variables:
|
||||
BUILD_ARCH: amd64
|
||||
@@ -185,12 +243,13 @@ publish-snap: &publish-snap
|
||||
tags:
|
||||
- linux-docker
|
||||
script:
|
||||
- scripts/gitlab/publish-snap.sh
|
||||
- ./tools/publish-snap.sh
|
||||
|
||||
publish-snap-i386:
|
||||
<<: *publish-snap
|
||||
variables:
|
||||
BUILD_ARCH: i386
|
||||
CARGO_TARGET: i686-unknown-linux-gnu
|
||||
dependencies:
|
||||
- build-linux-i386
|
||||
|
||||
@@ -198,6 +257,7 @@ publish-snap-arm64:
|
||||
<<: *publish-snap
|
||||
variables:
|
||||
BUILD_ARCH: arm64
|
||||
CARGO_TARGET: aarch64-unknown-linux-gnu
|
||||
dependencies:
|
||||
- build-linux-arm64
|
||||
|
||||
@@ -205,11 +265,13 @@ publish-snap-armhf:
|
||||
<<: *publish-snap
|
||||
variables:
|
||||
BUILD_ARCH: armhf
|
||||
CARGO_TARGET: armv7-unknown-linux-gnueabihf
|
||||
dependencies:
|
||||
- build-linux-armhf
|
||||
|
||||
publish-onchain:
|
||||
stage: publish
|
||||
<<: *no_git
|
||||
only: *releaseable_branches
|
||||
cache: {}
|
||||
dependencies:
|
||||
@@ -217,7 +279,7 @@ publish-onchain:
|
||||
- build-darwin
|
||||
- build-windows
|
||||
script:
|
||||
- scripts/gitlab/publish-onchain.sh
|
||||
- ./tools/publish-onchain.sh
|
||||
tags:
|
||||
- linux-docker
|
||||
|
||||
@@ -255,7 +317,9 @@ publish-docs:
|
||||
except:
|
||||
- nightly
|
||||
cache: {}
|
||||
dependencies: []
|
||||
script:
|
||||
- scripts/gitlab/publish-docs.sh
|
||||
tags:
|
||||
- linux-docker
|
||||
allow_failure: true
|
||||
|
||||
31
Cargo.lock
generated
31
Cargo.lock
generated
@@ -1282,6 +1282,7 @@ dependencies = [
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memory-cache 0.1.0",
|
||||
"num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-bytes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1545,7 +1546,7 @@ dependencies = [
|
||||
"libusb 0.3.0 (git+https://github.com/paritytech/libusb-rs)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"protobuf 1.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"protobuf 1.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"trezor-sys 1.0.0 (git+https://github.com/paritytech/trezor-sys)",
|
||||
@@ -2346,6 +2347,15 @@ dependencies = [
|
||||
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.39"
|
||||
@@ -2447,7 +2457,7 @@ dependencies = [
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"jni 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"panic_hook 0.1.0",
|
||||
"parity-ethereum 2.5.0",
|
||||
"parity-ethereum 2.5.3",
|
||||
"tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-current-thread 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -2477,7 +2487,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "parity-ethereum"
|
||||
version = "2.5.0"
|
||||
version = "2.5.3"
|
||||
dependencies = [
|
||||
"ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2530,7 +2540,7 @@ dependencies = [
|
||||
"parity-rpc 1.12.0",
|
||||
"parity-runtime 0.1.0",
|
||||
"parity-updater 1.12.0",
|
||||
"parity-version 2.5.0",
|
||||
"parity-version 2.5.3",
|
||||
"parity-whisper 0.1.0",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2673,7 +2683,7 @@ dependencies = [
|
||||
"parity-crypto 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-runtime 0.1.0",
|
||||
"parity-updater 1.12.0",
|
||||
"parity-version 2.5.0",
|
||||
"parity-version 2.5.3",
|
||||
"parking_lot 0.7.1 (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.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2771,7 +2781,7 @@ dependencies = [
|
||||
"parity-bytes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-hash-fetch 1.12.0",
|
||||
"parity-path 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-version 2.5.0",
|
||||
"parity-version 2.5.3",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2781,7 +2791,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "parity-version"
|
||||
version = "2.5.0"
|
||||
version = "2.5.3"
|
||||
dependencies = [
|
||||
"parity-bytes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rlp 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -3061,7 +3071,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "protobuf"
|
||||
version = "1.7.4"
|
||||
version = "1.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -4066,7 +4076,7 @@ name = "trezor-sys"
|
||||
version = "1.0.0"
|
||||
source = "git+https://github.com/paritytech/trezor-sys#8a401705e58c83db6c29c199d9577b78fde40709"
|
||||
dependencies = [
|
||||
"protobuf 1.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"protobuf 1.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4633,6 +4643,7 @@ dependencies = [
|
||||
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
|
||||
"checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e"
|
||||
"checksum num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1"
|
||||
"checksum num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "57450397855d951f1a41305e54851b1a7b8f5d2e349543a02a2effe25459f718"
|
||||
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
||||
"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
|
||||
"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
|
||||
@@ -4676,7 +4687,7 @@ dependencies = [
|
||||
"checksum primal-estimate 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "56ea4531dde757b56906493c8604641da14607bf9cdaa80fb9c9cabd2429f8d5"
|
||||
"checksum primal-sieve 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "da2d6ed369bb4b0273aeeb43f07c105c0117717cbae827b20719438eb2eb798c"
|
||||
"checksum proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "3d7b7eaaa90b4a90a932a9ea6666c95a389e424eff347f0f793979289429feee"
|
||||
"checksum protobuf 1.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "52fbc45bf6709565e44ef31847eb7407b3c3c80af811ee884a04da071dcca12b"
|
||||
"checksum protobuf 1.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e14ccd6b79ec748412d4f2dfde1a80fa363a67def4062969f8aed3d790a30f28"
|
||||
"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07"
|
||||
"checksum pwasm-utils 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e9135bed7b452e20dbb395a2d519abaf0c46d60e7ecc02daeeab447d29bada1"
|
||||
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
description = "Parity Ethereum client"
|
||||
name = "parity-ethereum"
|
||||
# NOTE Make sure to update util/version/Cargo.toml as well
|
||||
version = "2.5.0"
|
||||
version = "2.5.3"
|
||||
license = "GPL-3.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
@@ -118,10 +118,13 @@ path = "parity/lib.rs"
|
||||
path = "parity/main.rs"
|
||||
name = "parity"
|
||||
|
||||
[profile.dev]
|
||||
[profile.test]
|
||||
lto = false
|
||||
opt-level = 3 # makes tests slower to compile, but faster to run
|
||||
|
||||
[profile.release]
|
||||
debug = false
|
||||
lto = true
|
||||
|
||||
[workspace]
|
||||
# This should only list projects that are not
|
||||
|
||||
@@ -668,21 +668,6 @@ impl BlockChain {
|
||||
self.db.key_value().read_with_cache(db::COL_EXTRA, &self.block_details, parent).map_or(false, |d| d.children.contains(hash))
|
||||
}
|
||||
|
||||
/// fetches the list of blocks from best block to n, and n's parent hash
|
||||
/// where n > 0
|
||||
pub fn block_headers_from_best_block(&self, n: u32) -> Option<(Vec<encoded::Header>, H256)> {
|
||||
let mut blocks = Vec::with_capacity(n as usize);
|
||||
let mut hash = self.best_block_hash();
|
||||
|
||||
for _ in 0..n {
|
||||
let current_hash = self.block_header_data(&hash)?;
|
||||
hash = current_hash.parent_hash();
|
||||
blocks.push(current_hash);
|
||||
}
|
||||
|
||||
Some((blocks, hash))
|
||||
}
|
||||
|
||||
/// Returns a tree route between `from` and `to`, which is a tuple of:
|
||||
///
|
||||
/// - a vector of hashes of all blocks, ordered from `from` to `to`.
|
||||
@@ -869,6 +854,14 @@ impl BlockChain {
|
||||
}
|
||||
}
|
||||
|
||||
/// clears all caches for testing purposes
|
||||
pub fn clear_cache(&self) {
|
||||
self.block_bodies.write().clear();
|
||||
self.block_details.write().clear();
|
||||
self.block_hashes.write().clear();
|
||||
self.block_headers.write().clear();
|
||||
}
|
||||
|
||||
/// Update the best ancient block to the given hash, after checking that
|
||||
/// it's directly linked to the currently known best ancient block
|
||||
pub fn update_best_ancient_block(&self, hash: &H256) {
|
||||
|
||||
@@ -14,6 +14,7 @@ vm = { path = "../vm" }
|
||||
keccak-hash = "0.1"
|
||||
parking_lot = "0.7"
|
||||
memory-cache = { path = "../../util/memory-cache" }
|
||||
num-bigint = "0.2"
|
||||
|
||||
[dev-dependencies]
|
||||
rustc-hex = "1.0"
|
||||
|
||||
@@ -45,7 +45,9 @@ criterion_group!(
|
||||
mem_gas_calculation_same_usize,
|
||||
mem_gas_calculation_same_u256,
|
||||
mem_gas_calculation_increasing_usize,
|
||||
mem_gas_calculation_increasing_u256
|
||||
mem_gas_calculation_increasing_u256,
|
||||
blockhash_mulmod_small,
|
||||
blockhash_mulmod_large,
|
||||
);
|
||||
criterion_main!(basic);
|
||||
|
||||
@@ -150,6 +152,54 @@ fn mem_gas_calculation_increasing(gas: U256, b: &mut Bencher) {
|
||||
});
|
||||
}
|
||||
|
||||
fn blockhash_mulmod_small(b: &mut Criterion) {
|
||||
b.bench_function("blockhash_mulmod_small", |b| {
|
||||
let factory = Factory::default();
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||
|
||||
b.iter(|| {
|
||||
let code = black_box(
|
||||
"6080604052348015600f57600080fd5b5060005a90505b60c881111560de5760017effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80095060017effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80095060017effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80095060017effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80095060017effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8009505a90506016565b506035806100ed6000396000f3fe6080604052600080fdfea165627a7a72305820bde4a0ac6d0fac28fc879244baf8a6a0eda514bc95fb7ecbcaaebf2556e2687c0029".from_hex().unwrap()
|
||||
);
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.address = address.clone();
|
||||
params.gas = U256::from(4_000u64);
|
||||
params.code = Some(Arc::new(code.clone()));
|
||||
|
||||
let vm = factory.create(params, ext.schedule(), 0);
|
||||
|
||||
result(vm.exec(&mut ext).ok().unwrap())
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn blockhash_mulmod_large(b: &mut Criterion) {
|
||||
b.bench_function("blockhash_mulmod_large", |b| {
|
||||
let factory = Factory::default();
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||
|
||||
b.iter(|| {
|
||||
let code = black_box(
|
||||
"608060405234801561001057600080fd5b5060005a90505b60c8811115610177577efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff17efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff08009507efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff17efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff08009507efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff17efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff08009507efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff17efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff08009507efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff17efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff08009505a9050610017565b506035806101866000396000f3fe6080604052600080fdfea165627a7a72305820dcaec306f67bb96f3044fff25c9af2ec66f01d0954d0656964f046f42f2780670029".from_hex().unwrap()
|
||||
);
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.address = address.clone();
|
||||
params.gas = U256::from(4_000u64);
|
||||
params.code = Some(Arc::new(code.clone()));
|
||||
|
||||
let vm = factory.create(params, ext.schedule(), 0);
|
||||
|
||||
result(vm.exec(&mut ext).ok().unwrap())
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn result(r: Result<evm::GasLeft>) -> U256 {
|
||||
match r {
|
||||
Ok(GasLeft::Known(gas_left)) => gas_left,
|
||||
|
||||
@@ -28,7 +28,8 @@ use std::{cmp, mem};
|
||||
use std::sync::Arc;
|
||||
use hash::keccak;
|
||||
use bytes::Bytes;
|
||||
use ethereum_types::{U256, U512, H256, Address};
|
||||
use ethereum_types::{U256, H256, Address};
|
||||
use num_bigint::BigUint;
|
||||
|
||||
use vm::{
|
||||
self, ActionParams, ParamsType, ActionValue, CallType, MessageCallResult,
|
||||
@@ -61,6 +62,17 @@ const TWO_POW_96: U256 = U256([0, 0x100000000, 0, 0]); //0x1 00000000 00000000 0
|
||||
const TWO_POW_224: U256 = U256([0, 0, 0, 0x100000000]); //0x1 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
const TWO_POW_248: U256 = U256([0, 0, 0, 0x100000000000000]); //0x1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 000000
|
||||
|
||||
fn to_biguint(x: U256) -> BigUint {
|
||||
let mut bytes = [0u8; 32];
|
||||
x.to_little_endian(&mut bytes);
|
||||
BigUint::from_bytes_le(&bytes)
|
||||
}
|
||||
|
||||
fn from_biguint(x: BigUint) -> U256 {
|
||||
let bytes = x.to_bytes_le();
|
||||
U256::from_little_endian(&bytes)
|
||||
}
|
||||
|
||||
/// Abstraction over raw vector of Bytes. Easier state management of PC.
|
||||
struct CodeReader {
|
||||
position: ProgramCounter,
|
||||
@@ -1009,11 +1021,12 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
let c = self.stack.pop_back();
|
||||
|
||||
self.stack.push(if !c.is_zero() {
|
||||
// upcast to 512
|
||||
let a5 = U512::from(a);
|
||||
let res = a5.overflowing_add(U512::from(b)).0;
|
||||
let x = res % U512::from(c);
|
||||
U256::from(x)
|
||||
let a_num = to_biguint(a);
|
||||
let b_num = to_biguint(b);
|
||||
let c_num = to_biguint(c);
|
||||
let res = a_num + b_num;
|
||||
let x = res % c_num;
|
||||
from_biguint(x)
|
||||
} else {
|
||||
U256::zero()
|
||||
});
|
||||
@@ -1024,10 +1037,12 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
let c = self.stack.pop_back();
|
||||
|
||||
self.stack.push(if !c.is_zero() {
|
||||
let a5 = U512::from(a);
|
||||
let res = a5.overflowing_mul(U512::from(b)).0;
|
||||
let x = res % U512::from(c);
|
||||
U256::from(x)
|
||||
let a_num = to_biguint(a);
|
||||
let b_num = to_biguint(b);
|
||||
let c_num = to_biguint(c);
|
||||
let res = a_num * b_num;
|
||||
let x = res % c_num;
|
||||
from_biguint(x)
|
||||
} else {
|
||||
U256::zero()
|
||||
});
|
||||
|
||||
@@ -24,6 +24,7 @@ extern crate vm;
|
||||
extern crate keccak_hash as hash;
|
||||
extern crate memory_cache;
|
||||
extern crate parity_bytes as bytes;
|
||||
extern crate num_bigint;
|
||||
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
@@ -8,11 +8,12 @@
|
||||
"difficultyBoundDivisor": "0x0800",
|
||||
"durationLimit": "0x0d",
|
||||
"blockReward": "0x4563918244F40000",
|
||||
"homesteadTransition": 1150000,
|
||||
"ecip1010PauseTransition": 3000000,
|
||||
"ecip1010ContinueTransition": 5000000,
|
||||
"ecip1017EraRounds": 5000000,
|
||||
"bombDefuseTransition": 5900000
|
||||
"homesteadTransition": "0x118c30",
|
||||
"ecip1010PauseTransition": "0x2dc6c0",
|
||||
"ecip1010ContinueTransition": "0x4c4b40",
|
||||
"ecip1017EraRounds": "0x4c4b40",
|
||||
"eip100bTransition": "0x85d9a0",
|
||||
"bombDefuseTransition": "0x5a06e0"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -26,11 +27,17 @@
|
||||
"chainID": "0x3d",
|
||||
"forkBlock": "0x1d4c00",
|
||||
"forkCanonHash": "0x94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f",
|
||||
"eip150Transition": 2500000,
|
||||
"eip160Transition": 3000000,
|
||||
"eip161abcTransition": "0x7fffffffffffffff",
|
||||
"eip161dTransition": "0x7fffffffffffffff",
|
||||
"eip155Transition": 3000000
|
||||
"eip150Transition": "0x2625a0",
|
||||
"eip160Transition": "0x2dc6c0",
|
||||
"eip161abcTransition": "0x85d9a0",
|
||||
"eip161dTransition": "0x85d9a0",
|
||||
"eip155Transition": "0x2dc6c0",
|
||||
"maxCodeSize": "0x6000",
|
||||
"maxCodeSizeTransition": "0x85d9a0",
|
||||
"eip140Transition": "0x85d9a0",
|
||||
"eip211Transition": "0x85d9a0",
|
||||
"eip214Transition": "0x85d9a0",
|
||||
"eip658Transition": "0x85d9a0"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
@@ -3835,7 +3842,7 @@
|
||||
"0xc32fd5318214071a41cd8e98499b2b65942c5837c686a06b536146fd0bf294bf",
|
||||
"0xac390c012eecd83fa8f4cc77a59992914b5c95af36b28747e07adea13228acbc"
|
||||
]
|
||||
},
|
||||
},
|
||||
"nodes": [
|
||||
"enode://efd48ad0879eeb7f9cb5e50f33f7bc21e805a72e90361f145baaa22dd75d111e7cd9c93f1b7060dcb30aa1b3e620269336dbf32339fea4c18925a4c15fe642df@18.205.66.229:30303",
|
||||
"enode://5fbfb426fbb46f8b8c1bd3dd140f5b511da558cd37d60844b525909ab82e13a25ee722293c829e52cb65c2305b1637fa9a2ea4d6634a224d5f400bfe244ac0de@162.243.55.45:30303",
|
||||
@@ -3851,10 +3858,97 @@
|
||||
"enode://5cd218959f8263bc3721d7789070806b0adff1a0ed3f95ec886fb469f9362c7507e3b32b256550b9a7964a23a938e8d42d45a0c34b332bfebc54b29081e83b93@35.187.57.94:30303"
|
||||
],
|
||||
"accounts": {
|
||||
"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 } } } },
|
||||
"0x0000000000000000000000000000000000000001": {
|
||||
"builtin": {
|
||||
"name": "ecrecover",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 3000,
|
||||
"word": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000002": {
|
||||
"builtin": {
|
||||
"name": "sha256",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 60,
|
||||
"word": 12
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000003": {
|
||||
"builtin": {
|
||||
"name": "ripemd160",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 600,
|
||||
"word": 120
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000004": {
|
||||
"builtin": {
|
||||
"name": "identity",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 15,
|
||||
"word": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000005": {
|
||||
"builtin": {
|
||||
"name": "modexp",
|
||||
"activate_at": "0x85d9a0",
|
||||
"pricing": {
|
||||
"modexp": {
|
||||
"divisor": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000006": {
|
||||
"builtin": {
|
||||
"name": "alt_bn128_add",
|
||||
"activate_at": "0x85d9a0",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 500,
|
||||
"word": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000007": {
|
||||
"builtin": {
|
||||
"name": "alt_bn128_mul",
|
||||
"activate_at": "0x85d9a0",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 40000,
|
||||
"word": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000008": {
|
||||
"builtin": {
|
||||
"name": "alt_bn128_pairing",
|
||||
"activate_at": "0x85d9a0",
|
||||
"pricing": {
|
||||
"alt_bn128_pairing": {
|
||||
"base": 100000,
|
||||
"pair": 80000
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"3282791d6fd713f1e94f4bfd565eaa78b3a0599d": {
|
||||
"balance": "1337000000000000000000"
|
||||
},
|
||||
|
||||
@@ -48,8 +48,14 @@
|
||||
"timestamp": "0x5c51a607"
|
||||
},
|
||||
"nodes": [
|
||||
"enode://011f758e6552d105183b1761c5e2dea0111bc20fd5f6422bc7f91e0fabbec9a6595caf6239b37feb773dddd3f87240d99d859431891e4a642cf2a0a9e6cbb98a@51.141.78.53:30303",
|
||||
"enode://176b9417f511d05b6b2cf3e34b756cf0a7096b3094572a8f6ef4cdcb9d1f9d00683bf0f83347eebdf3b81c3521c2332086d9592802230bf528eaf606a1d9677b@13.93.54.137:30303"
|
||||
"enode://06333009fc9ef3c9e174768e495722a7f98fe7afd4660542e983005f85e556028410fd03278944f44cfe5437b1750b5e6bd1738f700fe7da3626d52010d2954c@51.141.15.254:30303",
|
||||
"enode://176b9417f511d05b6b2cf3e34b756cf0a7096b3094572a8f6ef4cdcb9d1f9d00683bf0f83347eebdf3b81c3521c2332086d9592802230bf528eaf606a1d9677b@13.93.54.137:30303",
|
||||
"enode://573b6607cd59f241e30e4c4943fd50e99e2b6f42f9bd5ca111659d309c06741247f4f1e93843ad3e8c8c18b6e2d94c161b7ef67479b3938780a97134b618b5ce@52.56.136.200:30303",
|
||||
"enode://67913271d14f445689e8310270c304d42f268428f2de7a4ac0275bea97690e021df6f549f462503ff4c7a81d9dd27288867bbfa2271477d0911378b8944fae55@157.230.239.163:30303",
|
||||
"enode://a87685902a0622e9cf18c68e73a0ea45156ec53e857ef049b185a9db2296ca04d776417bf1901c0b4eacb5b26271d8694e88e3f17c20d49eb77e1a41ab26b5b3@51.141.78.53:30303",
|
||||
"enode://ae8658da8d255d1992c3ec6e62e11d6e1c5899aa1566504bc1ff96a0c9c8bd44838372be643342553817f5cc7d78f1c83a8093dee13d77b3b0a583c050c81940@18.232.185.151:30303",
|
||||
"enode://ae8658da8d255d1992c3ec6e62e11d6e1c5899aa1566504bc1ff96a0c9c8bd44838372be643342553817f5cc7d78f1c83a8093dee13d77b3b0a583c050c81940@18.232.185.151:30303",
|
||||
"enode://b477ca6d507a3f57070783eb62ba838847635f8b1a0cbffb8b7f8173f5894cf550f0225a5c279341e2d862a606e778b57180a4f1db3db78c51eadcfa4fdc6963@40.68.240.160:30303"
|
||||
],
|
||||
"accounts": {
|
||||
"0x0000000000000000000000000000000000000000": {
|
||||
|
||||
@@ -12,12 +12,18 @@
|
||||
"params": {
|
||||
"accountStartNonce": "0x0",
|
||||
"chainID": "0x6",
|
||||
"eip140Transition": "0xaef49",
|
||||
"eip150Transition": "0x0",
|
||||
"eip155Transition": "0x0",
|
||||
"eip160Transition": "0x0",
|
||||
"eip161abcTransition": "0x7fffffffffffffff",
|
||||
"eip161dTransition": "0x7fffffffffffffff",
|
||||
"eip161abcTransition": "0xaef49",
|
||||
"eip161dTransition": "0xaef49",
|
||||
"eip211Transition": "0xaef49",
|
||||
"eip214Transition": "0xaef49",
|
||||
"eip658Transition": "0xaef49",
|
||||
"gasLimitBoundDivisor": "0x400",
|
||||
"maxCodeSize": "0x6000",
|
||||
"maxCodeSizeTransition": "0xaef49",
|
||||
"maximumExtraDataSize": "0xffff",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID": "0x6"
|
||||
@@ -38,7 +44,9 @@
|
||||
},
|
||||
"nodes": [
|
||||
"enode://06333009fc9ef3c9e174768e495722a7f98fe7afd4660542e983005f85e556028410fd03278944f44cfe5437b1750b5e6bd1738f700fe7da3626d52010d2954c@51.141.15.254:30303",
|
||||
"enode://ae8658da8d255d1992c3ec6e62e11d6e1c5899aa1566504bc1ff96a0c9c8bd44838372be643342553817f5cc7d78f1c83a8093dee13d77b3b0a583c050c81940@18.232.185.151:30303"
|
||||
"enode://93c94e999be5dd854c5d82a7cf5c14822973b5d9badb56ad4974586ec4d4f1995c815af795c20bb6e0a6226d3ee55808435c4dc89baf94ee581141b064d19dfc@80.187.116.161:25720",
|
||||
"enode://ae8658da8d255d1992c3ec6e62e11d6e1c5899aa1566504bc1ff96a0c9c8bd44838372be643342553817f5cc7d78f1c83a8093dee13d77b3b0a583c050c81940@18.232.185.151:30303",
|
||||
"enode://b477ca6d507a3f57070783eb62ba838847635f8b1a0cbffb8b7f8173f5894cf550f0225a5c279341e2d862a606e778b57180a4f1db3db78c51eadcfa4fdc6963@40.68.240.160:30303"
|
||||
],
|
||||
"accounts": {
|
||||
"0x0000000000000000000000000000000000000000": {
|
||||
@@ -93,16 +101,55 @@
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000005": {
|
||||
"balance": "0x1"
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "modexp",
|
||||
"activate_at": "0xaef49",
|
||||
"pricing": {
|
||||
"modexp": {
|
||||
"divisor": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000006": {
|
||||
"balance": "0x1"
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "alt_bn128_add",
|
||||
"activate_at": "0xaef49",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 500,
|
||||
"word": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000007": {
|
||||
"balance": "0x1"
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "alt_bn128_mul",
|
||||
"activate_at": "0xaef49",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 40000,
|
||||
"word": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000008": {
|
||||
"balance": "0x1"
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "alt_bn128_pairing",
|
||||
"activate_at": "0xaef49",
|
||||
"pricing": {
|
||||
"alt_bn128_pairing": {
|
||||
"base": 100000,
|
||||
"pair": 80000
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000009": {
|
||||
"balance": "0x1"
|
||||
|
||||
@@ -7,17 +7,31 @@
|
||||
"stepDuration": "0x4",
|
||||
"blockReward": "0x4563918244F40000",
|
||||
"validators": {
|
||||
"list": [
|
||||
"0x00D6Cc1BA9cf89BD2e58009741f4F7325BAdc0ED",
|
||||
"0x00427feae2419c15b89d1c21af10d1b6650a4d3d",
|
||||
"0x4Ed9B08e6354C70fE6F8CB0411b0d3246b424d6c",
|
||||
"0x0020ee4Be0e2027d76603cB751eE069519bA81A1",
|
||||
"0x0010f94b296a852aaac52ea6c5ac72e03afd032d",
|
||||
"0x007733a1FE69CF3f2CF989F81C7b4cAc1693387A",
|
||||
"0x00E6d2b931F55a3f1701c7389d592a7778897879",
|
||||
"0x00e4a10650e5a6D6001C38ff8E64F97016a1645c",
|
||||
"0x00a0a24b9f0e5ec7aa4c7389b8302fd0123194de"
|
||||
]
|
||||
"multi": {
|
||||
"0": {
|
||||
"list": [
|
||||
"0x00D6Cc1BA9cf89BD2e58009741f4F7325BAdc0ED",
|
||||
"0x00427feae2419c15b89d1c21af10d1b6650a4d3d",
|
||||
"0x4Ed9B08e6354C70fE6F8CB0411b0d3246b424d6c",
|
||||
"0x0020ee4Be0e2027d76603cB751eE069519bA81A1",
|
||||
"0x0010f94b296a852aaac52ea6c5ac72e03afd032d",
|
||||
"0x007733a1FE69CF3f2CF989F81C7b4cAc1693387A",
|
||||
"0x00E6d2b931F55a3f1701c7389d592a7778897879",
|
||||
"0x00e4a10650e5a6D6001C38ff8E64F97016a1645c",
|
||||
"0x00a0a24b9f0e5ec7aa4c7389b8302fd0123194de"
|
||||
]
|
||||
},
|
||||
"10960440": {
|
||||
"list": [
|
||||
"0x00D6Cc1BA9cf89BD2e58009741f4F7325BAdc0ED",
|
||||
"0x0010f94b296a852aaac52ea6c5ac72e03afd032d",
|
||||
"0x00a0a24b9f0e5ec7aa4c7389b8302fd0123194de"
|
||||
]
|
||||
},
|
||||
"10960500": {
|
||||
"safeContract": "0xaE71807C1B0a093cB1547b682DC78316D945c9B8"
|
||||
}
|
||||
}
|
||||
},
|
||||
"validateScoreTransition": "0x41a3c4",
|
||||
"validateStepTransition": "0x16e360",
|
||||
@@ -5367,6 +5381,7 @@
|
||||
}
|
||||
},
|
||||
"nodes": [
|
||||
"enode://f6e37b943bad3a78cb8589b1798d30d210ffd39cfcd2c8f2de4f098467fd49c667980100d919da7ca46cd50505d30989abda87f0b9339377de13d6592c22caf8@34.198.49.72:30303",
|
||||
"enode://56abaf065581a5985b8c5f4f88bd202526482761ba10be9bfdcd14846dd01f652ec33fde0f8c0fd1db19b59a4c04465681fcef50e11380ca88d25996191c52de@40.71.221.215:30303",
|
||||
"enode://d07827483dc47b368eaf88454fb04b41b7452cf454e194e2bd4c14f98a3278fed5d819dbecd0d010407fc7688d941ee1e58d4f9c6354d3da3be92f55c17d7ce3@52.166.117.77:30303",
|
||||
"enode://38e6e7fd416293ed120d567a2675fe078c0205ab0671abf16982ce969823bd1f3443d590c18b321dfae7dcbe1f6ba98ef8702f255c3c9822a188abb82c53adca@51.77.66.187:30303",
|
||||
|
||||
@@ -8,11 +8,12 @@
|
||||
"difficultyBoundDivisor": "0x0800",
|
||||
"durationLimit": "0x0d",
|
||||
"blockReward": "0x4563918244F40000",
|
||||
"homesteadTransition": 494000,
|
||||
"ecip1010PauseTransition": 1915000,
|
||||
"ecip1010ContinueTransition": 3415000,
|
||||
"ecip1017EraRounds": 2000000,
|
||||
"bombDefuseTransition": 2300000
|
||||
"homesteadTransition": "0x789b0",
|
||||
"ecip1010PauseTransition": "0x1d3878",
|
||||
"ecip1010ContinueTransition": "0x341bd8",
|
||||
"ecip1017EraRounds": "0x1e8480",
|
||||
"eip100bTransition": "0x4829ba",
|
||||
"bombDefuseTransition": "0x231860"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -26,11 +27,17 @@
|
||||
"chainID": "0x3e",
|
||||
"forkBlock": "0x1b34d8",
|
||||
"forkCanonHash": "0xf376243aeff1f256d970714c3de9fd78fa4e63cf63e32a51fe1169e375d98145",
|
||||
"eip150Transition": 1783000,
|
||||
"eip160Transition": 1915000,
|
||||
"eip161abcTransition": "0x7fffffffffffffff",
|
||||
"eip161dTransition": "0x7fffffffffffffff",
|
||||
"eip155Transition": 1915000
|
||||
"eip150Transition": "0x1b34d8",
|
||||
"eip160Transition": "0x1d3878",
|
||||
"eip161abcTransition": "0x4829ba",
|
||||
"eip161dTransition": "0x4829ba",
|
||||
"eip155Transition": "0x1d3878",
|
||||
"maxCodeSize": "0x6000",
|
||||
"maxCodeSizeTransition": "0x4829ba",
|
||||
"eip140Transition": "0x4829ba",
|
||||
"eip211Transition": "0x4829ba",
|
||||
"eip214Transition": "0x4829ba",
|
||||
"eip658Transition": "0x4829ba"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
@@ -68,6 +75,53 @@
|
||||
"0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||
"0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||
"0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
|
||||
"0x0000000000000000000000000000000000000005": {
|
||||
"builtin": {
|
||||
"name": "modexp",
|
||||
"activate_at": "0x4829ba",
|
||||
"pricing": {
|
||||
"modexp": {
|
||||
"divisor": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000006": {
|
||||
"builtin": {
|
||||
"name": "alt_bn128_add",
|
||||
"activate_at": "0x4829ba",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 500,
|
||||
"word": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000007": {
|
||||
"builtin": {
|
||||
"name": "alt_bn128_mul",
|
||||
"activate_at": "0x4829ba",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 40000,
|
||||
"word": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000008": {
|
||||
"builtin": {
|
||||
"name": "alt_bn128_pairing",
|
||||
"activate_at": "0x4829ba",
|
||||
"pricing": {
|
||||
"alt_bn128_pairing": {
|
||||
"base": 100000,
|
||||
"pair": 80000
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" }
|
||||
},
|
||||
"hardcodedSync": {
|
||||
|
||||
@@ -34,7 +34,10 @@
|
||||
"eip140Transition": "0x0",
|
||||
"eip211Transition": "0x0",
|
||||
"eip214Transition": "0x0",
|
||||
"eip658Transition": "0x0"
|
||||
"eip658Transition": "0x0",
|
||||
"eip145Transition": 8582254,
|
||||
"eip1014Transition": 8582254,
|
||||
"eip1052Transition": 8582254
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
"eip1014Transition": "0x37db77",
|
||||
"eip1052Transition": "0x37db77",
|
||||
"eip1283Transition": "0x37db77",
|
||||
"eip1283DisableTransition": "0x41efd2",
|
||||
"gasLimitBoundDivisor": "0x400",
|
||||
"maxCodeSize": "0x6000",
|
||||
"maxCodeSizeTransition": "0x0",
|
||||
|
||||
@@ -30,8 +30,10 @@ use blockchain::{BlockChainDB, BlockChainDBHandler};
|
||||
use ethcore::client::{Client, ClientConfig, ChainNotify, ClientIoMessage};
|
||||
use ethcore::miner::Miner;
|
||||
use ethcore::snapshot::service::{Service as SnapshotService, ServiceParams as SnapServiceParams};
|
||||
use ethcore::snapshot::{SnapshotService as _SnapshotService, RestorationStatus};
|
||||
use ethcore::snapshot::{SnapshotService as _SnapshotService, RestorationStatus, Error as SnapshotError};
|
||||
use ethcore::spec::Spec;
|
||||
use ethcore::error::{Error as EthcoreError, ErrorKind};
|
||||
|
||||
|
||||
use ethcore_private_tx::{self, Importer, Signer};
|
||||
use Error;
|
||||
@@ -197,6 +199,7 @@ impl ClientService {
|
||||
|
||||
/// Shutdown the Client Service
|
||||
pub fn shutdown(&self) {
|
||||
trace!(target: "shutdown", "Shutting down Client Service");
|
||||
self.snapshot.shutdown();
|
||||
}
|
||||
}
|
||||
@@ -257,7 +260,11 @@ impl IoHandler<ClientIoMessage> for ClientIoHandler {
|
||||
|
||||
let res = thread::Builder::new().name("Periodic Snapshot".into()).spawn(move || {
|
||||
if let Err(e) = snapshot.take_snapshot(&*client, num) {
|
||||
warn!("Failed to take snapshot at block #{}: {}", num, e);
|
||||
match e {
|
||||
EthcoreError(ErrorKind::Snapshot(SnapshotError::SnapshotAborted), _) => info!("Snapshot aborted"),
|
||||
_ => warn!("Failed to take snapshot at block #{}: {}", num, e),
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ use blockchain::{BlockReceipts, BlockChain, BlockChainDB, BlockProvider, TreeRou
|
||||
use bytes::Bytes;
|
||||
use call_contract::{CallContract, RegistryInfo};
|
||||
use ethcore_miner::pool::VerifiedTransaction;
|
||||
use ethereum_types::{H256, Address, U256};
|
||||
use ethereum_types::{H256, H264, Address, U256};
|
||||
use evm::Schedule;
|
||||
use hash::keccak;
|
||||
use io::IoChannel;
|
||||
@@ -86,7 +86,7 @@ pub use types::blockchain_info::BlockChainInfo;
|
||||
pub use types::block_status::BlockStatus;
|
||||
pub use blockchain::CacheSize as BlockChainCacheSize;
|
||||
pub use verification::QueueInfo as BlockQueueInfo;
|
||||
use db::Writable;
|
||||
use db::{Writable, Readable, keys::BlockDetails};
|
||||
|
||||
use_contract!(registry, "res/contracts/registrar.json");
|
||||
|
||||
@@ -764,8 +764,8 @@ impl Client {
|
||||
liveness: AtomicBool::new(awake),
|
||||
mode: Mutex::new(config.mode.clone()),
|
||||
chain: RwLock::new(chain),
|
||||
tracedb: tracedb,
|
||||
engine: engine,
|
||||
tracedb,
|
||||
engine,
|
||||
pruning: config.pruning.clone(),
|
||||
db: RwLock::new(db.clone()),
|
||||
state_db: RwLock::new(state_db),
|
||||
@@ -778,8 +778,8 @@ impl Client {
|
||||
ancient_blocks_import_lock: Default::default(),
|
||||
queue_consensus_message: IoChannelQueue::new(usize::max_value()),
|
||||
last_hashes: RwLock::new(VecDeque::new()),
|
||||
factories: factories,
|
||||
history: history,
|
||||
factories,
|
||||
history,
|
||||
on_user_defaults_change: Mutex::new(None),
|
||||
registrar_address,
|
||||
exit_handler: Mutex::new(None),
|
||||
@@ -1138,7 +1138,12 @@ impl Client {
|
||||
|
||||
/// Take a snapshot at the given block.
|
||||
/// If the ID given is "latest", this will default to 1000 blocks behind.
|
||||
pub fn take_snapshot<W: snapshot_io::SnapshotWriter + Send>(&self, writer: W, at: BlockId, p: &snapshot::Progress) -> Result<(), EthcoreError> {
|
||||
pub fn take_snapshot<W: snapshot_io::SnapshotWriter + Send>(
|
||||
&self,
|
||||
writer: W,
|
||||
at: BlockId,
|
||||
p: &snapshot::Progress,
|
||||
) -> Result<(), EthcoreError> {
|
||||
let db = self.state_db.read().journal_db().boxed_clone();
|
||||
let best_block_number = self.chain_info().best_block_number;
|
||||
let block_number = self.block_number(at).ok_or_else(|| snapshot::Error::InvalidStartingBlock(at))?;
|
||||
@@ -1168,8 +1173,16 @@ impl Client {
|
||||
};
|
||||
|
||||
let processing_threads = self.config.snapshot.processing_threads;
|
||||
snapshot::take_snapshot(&*self.engine, &self.chain.read(), start_hash, db.as_hash_db(), writer, p, processing_threads)?;
|
||||
|
||||
let chunker = self.engine.snapshot_components().ok_or(snapshot::Error::SnapshotsUnsupported)?;
|
||||
snapshot::take_snapshot(
|
||||
chunker,
|
||||
&self.chain.read(),
|
||||
start_hash,
|
||||
db.as_hash_db(),
|
||||
writer,
|
||||
p,
|
||||
processing_threads,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1327,37 +1340,60 @@ impl BlockChainReset for Client {
|
||||
fn reset(&self, num: u32) -> Result<(), String> {
|
||||
if num as u64 > self.pruning_history() {
|
||||
return Err("Attempting to reset to block with pruned state".into())
|
||||
} else if num == 0 {
|
||||
return Err("invalid number of blocks to reset".into())
|
||||
}
|
||||
|
||||
let (blocks_to_delete, best_block_hash) = self.chain.read()
|
||||
.block_headers_from_best_block(num)
|
||||
.ok_or("Attempted to reset past genesis block")?;
|
||||
let mut blocks_to_delete = Vec::with_capacity(num as usize);
|
||||
let mut best_block_hash = self.chain.read().best_block_hash();
|
||||
let mut batch = DBTransaction::with_capacity(blocks_to_delete.len());
|
||||
|
||||
let mut db_transaction = DBTransaction::with_capacity((num + 1) as usize);
|
||||
for _ in 0..num {
|
||||
let current_header = self.chain.read().block_header_data(&best_block_hash)
|
||||
.expect("best_block_hash was fetched from db; block_header_data should exist in db; qed");
|
||||
best_block_hash = current_header.parent_hash();
|
||||
|
||||
for hash in &blocks_to_delete {
|
||||
db_transaction.delete(::db::COL_HEADERS, &hash.hash());
|
||||
db_transaction.delete(::db::COL_BODIES, &hash.hash());
|
||||
db_transaction.delete(::db::COL_EXTRA, &hash.hash());
|
||||
let (number, hash) = (current_header.number(), current_header.hash());
|
||||
batch.delete(::db::COL_HEADERS, &hash);
|
||||
batch.delete(::db::COL_BODIES, &hash);
|
||||
Writable::delete::<BlockDetails, H264>
|
||||
(&mut batch, ::db::COL_EXTRA, &hash);
|
||||
Writable::delete::<H256, BlockNumberKey>
|
||||
(&mut db_transaction, ::db::COL_EXTRA, &hash.number());
|
||||
(&mut batch, ::db::COL_EXTRA, &number);
|
||||
|
||||
blocks_to_delete.push((number, hash));
|
||||
}
|
||||
|
||||
let hashes = blocks_to_delete.iter().map(|(_, hash)| hash).collect::<Vec<_>>();
|
||||
info!("Deleting block hashes {}",
|
||||
Colour::Red
|
||||
.bold()
|
||||
.paint(format!("{:#?}", hashes))
|
||||
);
|
||||
|
||||
let mut best_block_details = Readable::read::<BlockDetails, H264>(
|
||||
&**self.db.read().key_value(),
|
||||
::db::COL_EXTRA,
|
||||
&best_block_hash
|
||||
).expect("block was previously imported; best_block_details should exist; qed");
|
||||
|
||||
let (_, last_hash) = blocks_to_delete.last()
|
||||
.expect("num is > 0; blocks_to_delete can't be empty; qed");
|
||||
// remove the last block as a child so that it can be re-imported
|
||||
// ethcore/blockchain/src/blockchain.rs/Blockchain::is_known_child()
|
||||
best_block_details.children.retain(|h| *h != *last_hash);
|
||||
batch.write(
|
||||
::db::COL_EXTRA,
|
||||
&best_block_hash,
|
||||
&best_block_details
|
||||
);
|
||||
// update the new best block hash
|
||||
db_transaction.put(::db::COL_EXTRA, b"best", &*best_block_hash);
|
||||
batch.put(::db::COL_EXTRA, b"best", &best_block_hash);
|
||||
|
||||
self.db.read()
|
||||
.key_value()
|
||||
.write(db_transaction)
|
||||
.map_err(|err| format!("could not complete reset operation; io error occured: {}", err))?;
|
||||
|
||||
let hashes = blocks_to_delete.iter().map(|b| b.hash()).collect::<Vec<_>>();
|
||||
|
||||
info!("Deleting block hashes {}",
|
||||
Colour::Red
|
||||
.bold()
|
||||
.paint(format!("{:#?}", hashes))
|
||||
);
|
||||
.write(batch)
|
||||
.map_err(|err| format!("could not delete blocks; io error occurred: {}", err))?;
|
||||
|
||||
info!("New best block hash {}", Colour::Green.bold().paint(format!("{:?}", best_block_hash)));
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ 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, SystemTime, Duration};
|
||||
use std::time::{UNIX_EPOCH, Duration};
|
||||
|
||||
use block::*;
|
||||
use client::EngineClient;
|
||||
@@ -42,14 +42,12 @@ use itertools::{self, Itertools};
|
||||
use rlp::{encode, Decodable, DecoderError, Encodable, RlpStream, Rlp};
|
||||
use ethereum_types::{H256, H520, Address, U128, U256};
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use time_utils::CheckedSystemTime;
|
||||
use types::BlockNumber;
|
||||
use types::header::{Header, ExtendedHeader};
|
||||
use types::ancestry_action::AncestryAction;
|
||||
use unexpected::{Mismatch, OutOfBounds};
|
||||
|
||||
#[cfg(not(time_checked_add))]
|
||||
use time_utils::CheckedSystemTime;
|
||||
|
||||
mod finality;
|
||||
|
||||
/// `AuthorityRound` params.
|
||||
@@ -578,10 +576,10 @@ fn verify_timestamp(step: &Step, header_step: u64) -> Result<(), BlockError> {
|
||||
// Returning it further won't recover the sync process.
|
||||
trace!(target: "engine", "verify_timestamp: block too early");
|
||||
|
||||
let now = SystemTime::now();
|
||||
let found = now.checked_add(Duration::from_secs(oob.found)).ok_or(BlockError::TimestampOverflow)?;
|
||||
let max = oob.max.and_then(|m| now.checked_add(Duration::from_secs(m)));
|
||||
let min = oob.min.and_then(|m| now.checked_add(Duration::from_secs(m)));
|
||||
let found = CheckedSystemTime::checked_add(UNIX_EPOCH, Duration::from_secs(oob.found))
|
||||
.ok_or(BlockError::TimestampOverflow)?;
|
||||
let max = oob.max.and_then(|m| CheckedSystemTime::checked_add(UNIX_EPOCH, Duration::from_secs(m)));
|
||||
let min = oob.min.and_then(|m| CheckedSystemTime::checked_add(UNIX_EPOCH, Duration::from_secs(m)));
|
||||
|
||||
let new_oob = OutOfBounds { min, max, found };
|
||||
|
||||
|
||||
@@ -24,13 +24,11 @@ use engines::clique::{VoteType, DIFF_INTURN, DIFF_NOTURN, NULL_AUTHOR, SIGNING_D
|
||||
use error::{Error, BlockError};
|
||||
use ethereum_types::{Address, H64};
|
||||
use rand::Rng;
|
||||
use time_utils::CheckedSystemTime;
|
||||
use types::BlockNumber;
|
||||
use types::header::Header;
|
||||
use unexpected::Mismatch;
|
||||
|
||||
#[cfg(not(feature = "time_checked_add"))]
|
||||
use time_utils::CheckedSystemTime;
|
||||
|
||||
/// Type that keeps track of the state for a given vote
|
||||
// Votes that go against the proposal aren't counted since it's equivalent to not voting
|
||||
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
|
||||
@@ -268,7 +266,7 @@ impl CliqueBlockState {
|
||||
// This is a quite bad API because we must mutate both variables even when already `inturn` fails
|
||||
// That's why we can't return early and must have the `if-else` in the end
|
||||
pub fn calc_next_timestamp(&mut self, timestamp: u64, period: u64) -> Result<(), Error> {
|
||||
let inturn = UNIX_EPOCH.checked_add(Duration::from_secs(timestamp.saturating_add(period)));
|
||||
let inturn = CheckedSystemTime::checked_add(UNIX_EPOCH, Duration::from_secs(timestamp.saturating_add(period)));
|
||||
|
||||
self.next_timestamp_inturn = inturn;
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ use std::time;
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
|
||||
use block::ExecutedBlock;
|
||||
use bytes::Bytes;
|
||||
use client::{BlockId, EngineClient};
|
||||
use engines::clique::util::{extract_signers, recover_creator};
|
||||
use engines::{Engine, EngineError, Seal};
|
||||
@@ -81,12 +82,10 @@ use parking_lot::RwLock;
|
||||
use rand::Rng;
|
||||
use super::signer::EngineSigner;
|
||||
use unexpected::{Mismatch, OutOfBounds};
|
||||
use time_utils::CheckedSystemTime;
|
||||
use types::BlockNumber;
|
||||
use types::header::{ExtendedHeader, Header};
|
||||
|
||||
#[cfg(not(feature = "time_checked_add"))]
|
||||
use time_utils::CheckedSystemTime;
|
||||
|
||||
use self::block_state::CliqueBlockState;
|
||||
use self::params::CliqueParams;
|
||||
use self::step_service::StepService;
|
||||
@@ -535,7 +534,7 @@ impl Engine<EthereumMachine> for Clique {
|
||||
|
||||
// Don't waste time checking blocks from the future
|
||||
{
|
||||
let limit = SystemTime::now().checked_add(Duration::from_secs(self.period))
|
||||
let limit = CheckedSystemTime::checked_add(SystemTime::now(), Duration::from_secs(self.period))
|
||||
.ok_or(BlockError::TimestampOverflow)?;
|
||||
|
||||
// This should succeed under the contraints that the system clock works
|
||||
@@ -545,7 +544,7 @@ impl Engine<EthereumMachine> for Clique {
|
||||
|
||||
let hdr = Duration::from_secs(header.timestamp());
|
||||
if hdr > limit_as_dur {
|
||||
let found = UNIX_EPOCH.checked_add(hdr).ok_or(BlockError::TimestampOverflow)?;
|
||||
let found = CheckedSystemTime::checked_add(UNIX_EPOCH, hdr).ok_or(BlockError::TimestampOverflow)?;
|
||||
|
||||
Err(BlockError::TemporarilyInvalid(OutOfBounds {
|
||||
min: None,
|
||||
@@ -656,8 +655,8 @@ impl Engine<EthereumMachine> for Clique {
|
||||
// Ensure that the block's timestamp isn't too close to it's parent
|
||||
let limit = parent.timestamp().saturating_add(self.period);
|
||||
if limit > header.timestamp() {
|
||||
let max = UNIX_EPOCH.checked_add(Duration::from_secs(header.timestamp()));
|
||||
let found = UNIX_EPOCH.checked_add(Duration::from_secs(limit))
|
||||
let max = CheckedSystemTime::checked_add(UNIX_EPOCH, Duration::from_secs(header.timestamp()));
|
||||
let found = CheckedSystemTime::checked_add(UNIX_EPOCH, Duration::from_secs(limit))
|
||||
.ok_or(BlockError::TimestampOverflow)?;
|
||||
|
||||
Err(BlockError::InvalidTimestamp(OutOfBounds {
|
||||
@@ -713,6 +712,13 @@ impl Engine<EthereumMachine> for Clique {
|
||||
header.set_difficulty(DIFF_NOTURN);
|
||||
}
|
||||
}
|
||||
|
||||
let zero_padding_len = VANITY_LENGTH - header.extra_data().len();
|
||||
if zero_padding_len > 0 {
|
||||
let mut resized_extra_data = header.extra_data().clone();
|
||||
resized_extra_data.resize(VANITY_LENGTH, 0);
|
||||
header.set_extra_data(resized_extra_data);
|
||||
}
|
||||
} else {
|
||||
trace!(target: "engine", "populate_from_parent: no signer registered");
|
||||
}
|
||||
|
||||
@@ -314,7 +314,11 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
|
||||
}
|
||||
|
||||
fn extcodehash(&self, address: &Address) -> vm::Result<Option<H256>> {
|
||||
Ok(self.state.code_hash(address)?)
|
||||
if self.state.exists_and_not_null(address)? {
|
||||
Ok(self.state.code_hash(address)?)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn extcodesize(&self, address: &Address) -> vm::Result<Option<usize>> {
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#![warn(missing_docs, unused_extern_crates)]
|
||||
#![cfg_attr(feature = "time_checked_add", feature(time_checked_add))]
|
||||
|
||||
//! Ethcore library
|
||||
//!
|
||||
@@ -100,6 +99,7 @@ extern crate rlp;
|
||||
extern crate rustc_hex;
|
||||
extern crate serde;
|
||||
extern crate stats;
|
||||
extern crate time_utils;
|
||||
extern crate triehash_ethereum as triehash;
|
||||
extern crate unexpected;
|
||||
extern crate using_queue;
|
||||
@@ -149,9 +149,6 @@ extern crate fetch;
|
||||
#[cfg(all(test, feature = "price-info"))]
|
||||
extern crate parity_runtime;
|
||||
|
||||
#[cfg(not(time_checked_add))]
|
||||
extern crate time_utils;
|
||||
|
||||
pub mod block;
|
||||
pub mod builtin;
|
||||
pub mod client;
|
||||
|
||||
@@ -24,9 +24,10 @@ use ethtrie::{TrieDB, TrieDBMut};
|
||||
use hash::{KECCAK_EMPTY, KECCAK_NULL_RLP};
|
||||
use hash_db::HashDB;
|
||||
use rlp::{RlpStream, Rlp};
|
||||
use snapshot::Error;
|
||||
use snapshot::{Error, Progress};
|
||||
use std::collections::HashSet;
|
||||
use trie::{Trie, TrieMut};
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
// An empty account -- these were replaced with RLP null data for a space optimization in v1.
|
||||
const ACC_EMPTY: BasicAccount = BasicAccount {
|
||||
@@ -65,8 +66,16 @@ impl CodeState {
|
||||
// walk the account's storage trie, returning a vector of RLP items containing the
|
||||
// account address hash, account properties and the storage. Each item contains at most `max_storage_items`
|
||||
// storage records split according to snapshot format definition.
|
||||
pub fn to_fat_rlps(account_hash: &H256, acc: &BasicAccount, acct_db: &AccountDB, used_code: &mut HashSet<H256>, first_chunk_size: usize, max_chunk_size: usize) -> Result<Vec<Bytes>, Error> {
|
||||
let db = &(acct_db as &HashDB<_,_>);
|
||||
pub fn to_fat_rlps(
|
||||
account_hash: &H256,
|
||||
acc: &BasicAccount,
|
||||
acct_db: &AccountDB,
|
||||
used_code: &mut HashSet<H256>,
|
||||
first_chunk_size: usize,
|
||||
max_chunk_size: usize,
|
||||
p: &Progress,
|
||||
) -> Result<Vec<Bytes>, Error> {
|
||||
let db = &(acct_db as &dyn HashDB<_,_>);
|
||||
let db = TrieDB::new(db, &acc.storage_root)?;
|
||||
let mut chunks = Vec::new();
|
||||
let mut db_iter = db.iter()?;
|
||||
@@ -112,6 +121,10 @@ pub fn to_fat_rlps(account_hash: &H256, acc: &BasicAccount, acct_db: &AccountDB,
|
||||
}
|
||||
|
||||
loop {
|
||||
if p.abort.load(Ordering::SeqCst) {
|
||||
trace!(target: "snapshot", "to_fat_rlps: aborting snapshot");
|
||||
return Err(Error::SnapshotAborted);
|
||||
}
|
||||
match db_iter.next() {
|
||||
Some(Ok((k, v))) => {
|
||||
let pair = {
|
||||
@@ -211,6 +224,7 @@ mod tests {
|
||||
use types::basic_account::BasicAccount;
|
||||
use test_helpers::get_temp_state_db;
|
||||
use snapshot::tests::helpers::fill_storage;
|
||||
use snapshot::Progress;
|
||||
|
||||
use hash::{KECCAK_EMPTY, KECCAK_NULL_RLP, keccak};
|
||||
use ethereum_types::{H256, Address};
|
||||
@@ -236,8 +250,8 @@ mod tests {
|
||||
|
||||
let thin_rlp = ::rlp::encode(&account);
|
||||
assert_eq!(::rlp::decode::<BasicAccount>(&thin_rlp).unwrap(), account);
|
||||
|
||||
let fat_rlps = to_fat_rlps(&keccak(&addr), &account, &AccountDB::new(db.as_hash_db(), &addr), &mut Default::default(), usize::max_value(), usize::max_value()).unwrap();
|
||||
let p = Progress::default();
|
||||
let fat_rlps = to_fat_rlps(&keccak(&addr), &account, &AccountDB::new(db.as_hash_db(), &addr), &mut Default::default(), usize::max_value(), usize::max_value(), &p).unwrap();
|
||||
let fat_rlp = Rlp::new(&fat_rlps[0]).at(1).unwrap();
|
||||
assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hash_db_mut(), &addr), fat_rlp, H256::zero()).unwrap().0, account);
|
||||
}
|
||||
@@ -262,7 +276,9 @@ mod tests {
|
||||
let thin_rlp = ::rlp::encode(&account);
|
||||
assert_eq!(::rlp::decode::<BasicAccount>(&thin_rlp).unwrap(), account);
|
||||
|
||||
let fat_rlp = to_fat_rlps(&keccak(&addr), &account, &AccountDB::new(db.as_hash_db(), &addr), &mut Default::default(), usize::max_value(), usize::max_value()).unwrap();
|
||||
let p = Progress::default();
|
||||
|
||||
let fat_rlp = to_fat_rlps(&keccak(&addr), &account, &AccountDB::new(db.as_hash_db(), &addr), &mut Default::default(), usize::max_value(), usize::max_value(), &p).unwrap();
|
||||
let fat_rlp = Rlp::new(&fat_rlp[0]).at(1).unwrap();
|
||||
assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hash_db_mut(), &addr), fat_rlp, H256::zero()).unwrap().0, account);
|
||||
}
|
||||
@@ -287,7 +303,8 @@ mod tests {
|
||||
let thin_rlp = ::rlp::encode(&account);
|
||||
assert_eq!(::rlp::decode::<BasicAccount>(&thin_rlp).unwrap(), account);
|
||||
|
||||
let fat_rlps = to_fat_rlps(&keccak(addr), &account, &AccountDB::new(db.as_hash_db(), &addr), &mut Default::default(), 500, 1000).unwrap();
|
||||
let p = Progress::default();
|
||||
let fat_rlps = to_fat_rlps(&keccak(addr), &account, &AccountDB::new(db.as_hash_db(), &addr), &mut Default::default(), 500, 1000, &p).unwrap();
|
||||
let mut root = KECCAK_NULL_RLP;
|
||||
let mut restored_account = None;
|
||||
for rlp in fat_rlps {
|
||||
@@ -319,20 +336,21 @@ mod tests {
|
||||
nonce: 50.into(),
|
||||
balance: 123456789.into(),
|
||||
storage_root: KECCAK_NULL_RLP,
|
||||
code_hash: code_hash,
|
||||
code_hash,
|
||||
};
|
||||
|
||||
let account2 = BasicAccount {
|
||||
nonce: 400.into(),
|
||||
balance: 98765432123456789usize.into(),
|
||||
storage_root: KECCAK_NULL_RLP,
|
||||
code_hash: code_hash,
|
||||
code_hash,
|
||||
};
|
||||
|
||||
let mut used_code = HashSet::new();
|
||||
|
||||
let fat_rlp1 = to_fat_rlps(&keccak(&addr1), &account1, &AccountDB::new(db.as_hash_db(), &addr1), &mut used_code, usize::max_value(), usize::max_value()).unwrap();
|
||||
let fat_rlp2 = to_fat_rlps(&keccak(&addr2), &account2, &AccountDB::new(db.as_hash_db(), &addr2), &mut used_code, usize::max_value(), usize::max_value()).unwrap();
|
||||
let p1 = Progress::default();
|
||||
let p2 = Progress::default();
|
||||
let fat_rlp1 = to_fat_rlps(&keccak(&addr1), &account1, &AccountDB::new(db.as_hash_db(), &addr1), &mut used_code, usize::max_value(), usize::max_value(), &p1).unwrap();
|
||||
let fat_rlp2 = to_fat_rlps(&keccak(&addr2), &account2, &AccountDB::new(db.as_hash_db(), &addr2), &mut used_code, usize::max_value(), usize::max_value(), &p2).unwrap();
|
||||
assert_eq!(used_code.len(), 1);
|
||||
|
||||
let fat_rlp1 = Rlp::new(&fat_rlp1[0]).at(1).unwrap();
|
||||
@@ -350,6 +368,6 @@ mod tests {
|
||||
#[test]
|
||||
fn encoding_empty_acc() {
|
||||
let mut db = get_temp_state_db();
|
||||
assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hash_db_mut(), &Address::default()), Rlp::new(&::rlp::NULL_RLP), H256::zero()).unwrap(), (ACC_EMPTY, None));
|
||||
assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hash_db_mut(), &Address::zero()), Rlp::new(&::rlp::NULL_RLP), H256::zero()).unwrap(), (ACC_EMPTY, None));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,8 @@ pub enum Error {
|
||||
ChunkTooLarge,
|
||||
/// Snapshots not supported by the consensus engine.
|
||||
SnapshotsUnsupported,
|
||||
/// Aborted snapshot
|
||||
SnapshotAborted,
|
||||
/// Bad epoch transition.
|
||||
BadEpochProof(u64),
|
||||
/// Wrong chunk format.
|
||||
@@ -91,6 +93,7 @@ impl fmt::Display for Error {
|
||||
Error::ChunkTooSmall => write!(f, "Chunk size is too small."),
|
||||
Error::ChunkTooLarge => write!(f, "Chunk size is too large."),
|
||||
Error::SnapshotsUnsupported => write!(f, "Snapshots unsupported by consensus engine."),
|
||||
Error::SnapshotAborted => write!(f, "Snapshot was aborted."),
|
||||
Error::BadEpochProof(i) => write!(f, "Bad epoch proof for transition to epoch {}", i),
|
||||
Error::WrongChunkFormat(ref msg) => write!(f, "Wrong chunk format: {}", msg),
|
||||
Error::UnlinkedAncientBlockChain => write!(f, "Unlinked ancient blocks chain"),
|
||||
|
||||
@@ -310,10 +310,7 @@ impl LooseReader {
|
||||
|
||||
dir.pop();
|
||||
|
||||
Ok(LooseReader {
|
||||
dir: dir,
|
||||
manifest: manifest,
|
||||
})
|
||||
Ok(LooseReader { dir, manifest })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::cmp;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
use std::sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering};
|
||||
use hash::{keccak, KECCAK_NULL_RLP, KECCAK_EMPTY};
|
||||
|
||||
use account_db::{AccountDB, AccountDBMut};
|
||||
@@ -107,7 +107,7 @@ impl Default for SnapshotConfiguration {
|
||||
fn default() -> Self {
|
||||
SnapshotConfiguration {
|
||||
no_periodic: false,
|
||||
processing_threads: ::std::cmp::max(1, num_cpus::get() / 2),
|
||||
processing_threads: ::std::cmp::max(1, num_cpus::get_physical() / 2),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,8 +117,9 @@ impl Default for SnapshotConfiguration {
|
||||
pub struct Progress {
|
||||
accounts: AtomicUsize,
|
||||
blocks: AtomicUsize,
|
||||
size: AtomicUsize, // Todo [rob] use Atomicu64 when it stabilizes.
|
||||
size: AtomicU64,
|
||||
done: AtomicBool,
|
||||
abort: AtomicBool,
|
||||
}
|
||||
|
||||
impl Progress {
|
||||
@@ -127,6 +128,7 @@ impl Progress {
|
||||
self.accounts.store(0, Ordering::Release);
|
||||
self.blocks.store(0, Ordering::Release);
|
||||
self.size.store(0, Ordering::Release);
|
||||
self.abort.store(false, Ordering::Release);
|
||||
|
||||
// atomic fence here to ensure the others are written first?
|
||||
// logs might very rarely get polluted if not.
|
||||
@@ -140,7 +142,7 @@ impl Progress {
|
||||
pub fn blocks(&self) -> usize { self.blocks.load(Ordering::Acquire) }
|
||||
|
||||
/// Get the written size of the snapshot in bytes.
|
||||
pub fn size(&self) -> usize { self.size.load(Ordering::Acquire) }
|
||||
pub fn size(&self) -> u64 { self.size.load(Ordering::Acquire) }
|
||||
|
||||
/// Whether the snapshot is complete.
|
||||
pub fn done(&self) -> bool { self.done.load(Ordering::Acquire) }
|
||||
@@ -148,27 +150,28 @@ impl Progress {
|
||||
}
|
||||
/// Take a snapshot using the given blockchain, starting block hash, and database, writing into the given writer.
|
||||
pub fn take_snapshot<W: SnapshotWriter + Send>(
|
||||
engine: &EthEngine,
|
||||
chunker: Box<dyn SnapshotComponents>,
|
||||
chain: &BlockChain,
|
||||
block_at: H256,
|
||||
state_db: &HashDB<KeccakHasher, DBValue>,
|
||||
block_hash: H256,
|
||||
state_db: &dyn HashDB<KeccakHasher, DBValue>,
|
||||
writer: W,
|
||||
p: &Progress,
|
||||
processing_threads: usize,
|
||||
) -> Result<(), Error> {
|
||||
let start_header = chain.block_header_data(&block_at)
|
||||
.ok_or_else(|| Error::InvalidStartingBlock(BlockId::Hash(block_at)))?;
|
||||
let start_header = chain.block_header_data(&block_hash)
|
||||
.ok_or_else(|| Error::InvalidStartingBlock(BlockId::Hash(block_hash)))?;
|
||||
let state_root = start_header.state_root();
|
||||
let number = start_header.number();
|
||||
let block_number = start_header.number();
|
||||
|
||||
info!("Taking snapshot starting at block {}", number);
|
||||
info!("Taking snapshot starting at block {}", block_number);
|
||||
|
||||
let version = chunker.current_version();
|
||||
let writer = Mutex::new(writer);
|
||||
let chunker = engine.snapshot_components().ok_or(Error::SnapshotsUnsupported)?;
|
||||
let snapshot_version = chunker.current_version();
|
||||
let (state_hashes, block_hashes) = scope(|scope| -> Result<(Vec<H256>, Vec<H256>), Error> {
|
||||
let writer = &writer;
|
||||
let block_guard = scope.spawn(move || chunk_secondary(chunker, chain, block_at, writer, p));
|
||||
let block_guard = scope.spawn(move || {
|
||||
chunk_secondary(chunker, chain, block_hash, writer, p)
|
||||
});
|
||||
|
||||
// The number of threads must be between 1 and SNAPSHOT_SUBPARTS
|
||||
assert!(processing_threads >= 1, "Cannot use less than 1 threads for creating snapshots");
|
||||
@@ -183,7 +186,7 @@ pub fn take_snapshot<W: SnapshotWriter + Send>(
|
||||
|
||||
for part in (thread_idx..SNAPSHOT_SUBPARTS).step_by(num_threads) {
|
||||
debug!(target: "snapshot", "Chunking part {} in thread {}", part, thread_idx);
|
||||
let mut hashes = chunk_state(state_db, &state_root, writer, p, Some(part))?;
|
||||
let mut hashes = chunk_state(state_db, &state_root, writer, p, Some(part), thread_idx)?;
|
||||
chunk_hashes.append(&mut hashes);
|
||||
}
|
||||
|
||||
@@ -207,12 +210,12 @@ pub fn take_snapshot<W: SnapshotWriter + Send>(
|
||||
info!(target: "snapshot", "produced {} state chunks and {} block chunks.", state_hashes.len(), block_hashes.len());
|
||||
|
||||
let manifest_data = ManifestData {
|
||||
version: snapshot_version,
|
||||
state_hashes: state_hashes,
|
||||
block_hashes: block_hashes,
|
||||
state_root: state_root,
|
||||
block_number: number,
|
||||
block_hash: block_at,
|
||||
version,
|
||||
state_hashes,
|
||||
block_hashes,
|
||||
state_root,
|
||||
block_number,
|
||||
block_hash,
|
||||
};
|
||||
|
||||
writer.into_inner().finish(manifest_data)?;
|
||||
@@ -228,7 +231,13 @@ pub fn take_snapshot<W: SnapshotWriter + Send>(
|
||||
/// Secondary chunks are engine-specific, but they intend to corroborate the state data
|
||||
/// in the state chunks.
|
||||
/// Returns a list of chunk hashes, with the first having the blocks furthest from the genesis.
|
||||
pub fn chunk_secondary<'a>(mut chunker: Box<SnapshotComponents>, chain: &'a BlockChain, start_hash: H256, writer: &Mutex<SnapshotWriter + 'a>, progress: &'a Progress) -> Result<Vec<H256>, Error> {
|
||||
pub fn chunk_secondary<'a>(
|
||||
mut chunker: Box<dyn SnapshotComponents>,
|
||||
chain: &'a BlockChain,
|
||||
start_hash: H256,
|
||||
writer: &Mutex<dyn SnapshotWriter + 'a>,
|
||||
progress: &'a Progress
|
||||
) -> Result<Vec<H256>, Error> {
|
||||
let mut chunk_hashes = Vec::new();
|
||||
let mut snappy_buffer = vec![0; snappy::max_compressed_len(PREFERRED_CHUNK_SIZE)];
|
||||
|
||||
@@ -243,7 +252,7 @@ pub fn chunk_secondary<'a>(mut chunker: Box<SnapshotComponents>, chain: &'a Bloc
|
||||
trace!(target: "snapshot", "wrote secondary chunk. hash: {:x}, size: {}, uncompressed size: {}",
|
||||
hash, size, raw_data.len());
|
||||
|
||||
progress.size.fetch_add(size, Ordering::SeqCst);
|
||||
progress.size.fetch_add(size as u64, Ordering::SeqCst);
|
||||
chunk_hashes.push(hash);
|
||||
Ok(())
|
||||
};
|
||||
@@ -266,8 +275,9 @@ struct StateChunker<'a> {
|
||||
rlps: Vec<Bytes>,
|
||||
cur_size: usize,
|
||||
snappy_buffer: Vec<u8>,
|
||||
writer: &'a Mutex<SnapshotWriter + 'a>,
|
||||
writer: &'a Mutex<dyn SnapshotWriter + 'a>,
|
||||
progress: &'a Progress,
|
||||
thread_idx: usize,
|
||||
}
|
||||
|
||||
impl<'a> StateChunker<'a> {
|
||||
@@ -297,10 +307,10 @@ impl<'a> StateChunker<'a> {
|
||||
let hash = keccak(&compressed);
|
||||
|
||||
self.writer.lock().write_state_chunk(hash, compressed)?;
|
||||
trace!(target: "snapshot", "wrote state chunk. size: {}, uncompressed size: {}", compressed_size, raw_data.len());
|
||||
trace!(target: "snapshot", "Thread {} wrote state chunk. size: {}, uncompressed size: {}", self.thread_idx, compressed_size, raw_data.len());
|
||||
|
||||
self.progress.accounts.fetch_add(num_entries, Ordering::SeqCst);
|
||||
self.progress.size.fetch_add(compressed_size, Ordering::SeqCst);
|
||||
self.progress.size.fetch_add(compressed_size as u64, Ordering::SeqCst);
|
||||
|
||||
self.hashes.push(hash);
|
||||
self.cur_size = 0;
|
||||
@@ -321,7 +331,14 @@ impl<'a> StateChunker<'a> {
|
||||
///
|
||||
/// Returns a list of hashes of chunks created, or any error it may
|
||||
/// have encountered.
|
||||
pub fn chunk_state<'a>(db: &HashDB<KeccakHasher, DBValue>, root: &H256, writer: &Mutex<SnapshotWriter + 'a>, progress: &'a Progress, part: Option<usize>) -> Result<Vec<H256>, Error> {
|
||||
pub fn chunk_state<'a>(
|
||||
db: &dyn HashDB<KeccakHasher, DBValue>,
|
||||
root: &H256,
|
||||
writer: &Mutex<dyn SnapshotWriter + 'a>,
|
||||
progress: &'a Progress,
|
||||
part: Option<usize>,
|
||||
thread_idx: usize,
|
||||
) -> Result<Vec<H256>, Error> {
|
||||
let account_trie = TrieDB::new(&db, &root)?;
|
||||
|
||||
let mut chunker = StateChunker {
|
||||
@@ -329,8 +346,9 @@ pub fn chunk_state<'a>(db: &HashDB<KeccakHasher, DBValue>, root: &H256, writer:
|
||||
rlps: Vec::new(),
|
||||
cur_size: 0,
|
||||
snappy_buffer: vec![0; snappy::max_compressed_len(PREFERRED_CHUNK_SIZE)],
|
||||
writer: writer,
|
||||
progress: progress,
|
||||
writer,
|
||||
progress,
|
||||
thread_idx,
|
||||
};
|
||||
|
||||
let mut used_code = HashSet::new();
|
||||
@@ -365,7 +383,7 @@ pub fn chunk_state<'a>(db: &HashDB<KeccakHasher, DBValue>, root: &H256, writer:
|
||||
let account = ::rlp::decode(&*account_data)?;
|
||||
let account_db = AccountDB::from_hash(db, account_key_hash);
|
||||
|
||||
let fat_rlps = account::to_fat_rlps(&account_key_hash, &account, &account_db, &mut used_code, PREFERRED_CHUNK_SIZE - chunker.chunk_size(), PREFERRED_CHUNK_SIZE)?;
|
||||
let fat_rlps = account::to_fat_rlps(&account_key_hash, &account, &account_db, &mut used_code, PREFERRED_CHUNK_SIZE - chunker.chunk_size(), PREFERRED_CHUNK_SIZE, progress)?;
|
||||
for (i, fat_rlp) in fat_rlps.into_iter().enumerate() {
|
||||
if i > 0 {
|
||||
chunker.write_chunk()?;
|
||||
@@ -383,7 +401,7 @@ pub fn chunk_state<'a>(db: &HashDB<KeccakHasher, DBValue>, root: &H256, writer:
|
||||
|
||||
/// Used to rebuild the state trie piece by piece.
|
||||
pub struct StateRebuilder {
|
||||
db: Box<JournalDB>,
|
||||
db: Box<dyn JournalDB>,
|
||||
state_root: H256,
|
||||
known_code: HashMap<H256, H256>, // code hashes mapped to first account with this code.
|
||||
missing_code: HashMap<H256, Vec<H256>>, // maps code hashes to lists of accounts missing that code.
|
||||
@@ -393,7 +411,7 @@ pub struct StateRebuilder {
|
||||
|
||||
impl StateRebuilder {
|
||||
/// Create a new state rebuilder to write into the given backing DB.
|
||||
pub fn new(db: Arc<KeyValueDB>, pruning: Algorithm) -> Self {
|
||||
pub fn new(db: Arc<dyn KeyValueDB>, pruning: Algorithm) -> Self {
|
||||
StateRebuilder {
|
||||
db: journaldb::new(db.clone(), pruning, ::db::COL_STATE),
|
||||
state_root: KECCAK_NULL_RLP,
|
||||
@@ -411,7 +429,7 @@ impl StateRebuilder {
|
||||
let mut pairs = Vec::with_capacity(rlp.item_count()?);
|
||||
|
||||
// initialize the pairs vector with empty values so we have slots to write into.
|
||||
pairs.resize(rlp.item_count()?, (H256::new(), Vec::new()));
|
||||
pairs.resize(rlp.item_count()?, (H256::zero(), Vec::new()));
|
||||
|
||||
let status = rebuild_accounts(
|
||||
self.db.as_hash_db_mut(),
|
||||
@@ -468,7 +486,7 @@ impl StateRebuilder {
|
||||
/// Finalize the restoration. Check for accounts missing code and make a dummy
|
||||
/// journal entry.
|
||||
/// Once all chunks have been fed, there should be nothing missing.
|
||||
pub fn finalize(mut self, era: u64, id: H256) -> Result<Box<JournalDB>, ::error::Error> {
|
||||
pub fn finalize(mut self, era: u64, id: H256) -> Result<Box<dyn JournalDB>, ::error::Error> {
|
||||
let missing = self.missing_code.keys().cloned().collect::<Vec<_>>();
|
||||
if !missing.is_empty() { return Err(Error::MissingCode(missing).into()) }
|
||||
|
||||
@@ -493,7 +511,7 @@ struct RebuiltStatus {
|
||||
// rebuild a set of accounts and their storage.
|
||||
// returns a status detailing newly-loaded code and accounts missing code.
|
||||
fn rebuild_accounts(
|
||||
db: &mut HashDB<KeccakHasher, DBValue>,
|
||||
db: &mut dyn HashDB<KeccakHasher, DBValue>,
|
||||
account_fat_rlps: Rlp,
|
||||
out_chunk: &mut [(H256, Bytes)],
|
||||
known_code: &HashMap<H256, H256>,
|
||||
@@ -560,7 +578,7 @@ const POW_VERIFY_RATE: f32 = 0.02;
|
||||
/// Verify an old block with the given header, engine, blockchain, body. If `always` is set, it will perform
|
||||
/// the fullest verification possible. If not, it will take a random sample to determine whether it will
|
||||
/// do heavy or light verification.
|
||||
pub fn verify_old_block(rng: &mut OsRng, header: &Header, engine: &EthEngine, chain: &BlockChain, always: bool) -> Result<(), ::error::Error> {
|
||||
pub fn verify_old_block(rng: &mut OsRng, header: &Header, engine: &dyn EthEngine, chain: &BlockChain, always: bool) -> Result<(), ::error::Error> {
|
||||
engine.verify_block_basic(header)?;
|
||||
|
||||
if always || rng.gen::<f32>() <= POW_VERIFY_RATE {
|
||||
|
||||
@@ -415,7 +415,7 @@ impl Service {
|
||||
_ => break,
|
||||
}
|
||||
|
||||
// Writting changes to DB and logging every now and then
|
||||
// Writing changes to DB and logging every now and then
|
||||
if block_number % 1_000 == 0 {
|
||||
next_db.key_value().write_buffered(batch);
|
||||
next_chain.commit();
|
||||
@@ -479,16 +479,12 @@ impl Service {
|
||||
|
||||
let guard = Guard::new(temp_dir.clone());
|
||||
let res = client.take_snapshot(writer, BlockId::Number(num), &self.progress);
|
||||
|
||||
self.taking_snapshot.store(false, Ordering::SeqCst);
|
||||
if let Err(e) = res {
|
||||
if client.chain_info().best_block_number >= num + client.pruning_history() {
|
||||
// "Cancelled" is mincing words a bit -- what really happened
|
||||
// is that the state we were snapshotting got pruned out
|
||||
// before we could finish.
|
||||
info!("Periodic snapshot failed: block state pruned.\
|
||||
Run with a longer `--pruning-history` or with `--no-periodic-snapshot`");
|
||||
return Ok(())
|
||||
// The state we were snapshotting was pruned before we could finish.
|
||||
info!("Periodic snapshot failed: block state pruned. Run with a longer `--pruning-history` or with `--no-periodic-snapshot`");
|
||||
return Err(e);
|
||||
} else {
|
||||
return Err(e);
|
||||
}
|
||||
@@ -846,14 +842,29 @@ impl SnapshotService for Service {
|
||||
}
|
||||
}
|
||||
|
||||
fn abort_snapshot(&self) {
|
||||
if self.taking_snapshot.load(Ordering::SeqCst) {
|
||||
trace!(target: "snapshot", "Aborting snapshot – Snapshot under way");
|
||||
self.progress.abort.store(true, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
fn shutdown(&self) {
|
||||
trace!(target: "snapshot", "Shut down SnapshotService");
|
||||
self.abort_restore();
|
||||
trace!(target: "snapshot", "Shut down SnapshotService - restore aborted");
|
||||
self.abort_snapshot();
|
||||
trace!(target: "snapshot", "Shut down SnapshotService - snapshot aborted");
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Service {
|
||||
fn drop(&mut self) {
|
||||
trace!(target: "shutdown", "Dropping Service");
|
||||
self.abort_restore();
|
||||
trace!(target: "shutdown", "Dropping Service - restore aborted");
|
||||
self.abort_snapshot();
|
||||
trace!(target: "shutdown", "Dropping Service - snapshot aborted");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -188,14 +188,15 @@ fn keep_ancient_blocks() {
|
||||
&state_root,
|
||||
&writer,
|
||||
&Progress::default(),
|
||||
None
|
||||
None,
|
||||
0
|
||||
).unwrap();
|
||||
|
||||
let manifest = ::snapshot::ManifestData {
|
||||
version: 2,
|
||||
state_hashes: state_hashes,
|
||||
state_root: state_root,
|
||||
block_hashes: block_hashes,
|
||||
state_hashes,
|
||||
state_root,
|
||||
block_hashes,
|
||||
block_number: NUM_BLOCKS,
|
||||
block_hash: best_hash,
|
||||
};
|
||||
|
||||
@@ -55,7 +55,7 @@ fn snap_and_restore() {
|
||||
|
||||
let mut state_hashes = Vec::new();
|
||||
for part in 0..SNAPSHOT_SUBPARTS {
|
||||
let mut hashes = chunk_state(&old_db, &state_root, &writer, &Progress::default(), Some(part)).unwrap();
|
||||
let mut hashes = chunk_state(&old_db, &state_root, &writer, &Progress::default(), Some(part), 0).unwrap();
|
||||
state_hashes.append(&mut hashes);
|
||||
}
|
||||
|
||||
@@ -126,8 +126,8 @@ fn get_code_from_prev_chunk() {
|
||||
let mut make_chunk = |acc, hash| {
|
||||
let mut db = journaldb::new_memory_db();
|
||||
AccountDBMut::from_hash(&mut db, hash).insert(&code[..]);
|
||||
|
||||
let fat_rlp = account::to_fat_rlps(&hash, &acc, &AccountDB::from_hash(&db, hash), &mut used_code, usize::max_value(), usize::max_value()).unwrap();
|
||||
let p = Progress::default();
|
||||
let fat_rlp = account::to_fat_rlps(&hash, &acc, &AccountDB::from_hash(&db, hash), &mut used_code, usize::max_value(), usize::max_value(), &p).unwrap();
|
||||
let mut stream = RlpStream::new_list(1);
|
||||
stream.append_raw(&fat_rlp[0], 1);
|
||||
stream.out()
|
||||
@@ -171,13 +171,13 @@ fn checks_flag() {
|
||||
let state_root = producer.state_root();
|
||||
let writer = Mutex::new(PackedWriter::new(&snap_file).unwrap());
|
||||
|
||||
let state_hashes = chunk_state(&old_db, &state_root, &writer, &Progress::default(), None).unwrap();
|
||||
let state_hashes = chunk_state(&old_db, &state_root, &writer, &Progress::default(), None, 0).unwrap();
|
||||
|
||||
writer.into_inner().finish(::snapshot::ManifestData {
|
||||
version: 2,
|
||||
state_hashes: state_hashes,
|
||||
state_hashes,
|
||||
block_hashes: Vec::new(),
|
||||
state_root: state_root,
|
||||
state_root,
|
||||
block_number: 0,
|
||||
block_hash: H256::default(),
|
||||
}).unwrap();
|
||||
|
||||
@@ -55,6 +55,9 @@ pub trait SnapshotService : Sync + Send {
|
||||
/// no-op if currently restoring.
|
||||
fn restore_block_chunk(&self, hash: H256, chunk: Bytes);
|
||||
|
||||
/// Abort in-progress snapshotting if there is one.
|
||||
fn abort_snapshot(&self);
|
||||
|
||||
/// Shutdown the Snapshot Service by aborting any ongoing restore
|
||||
fn shutdown(&self);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ use types::filter::Filter;
|
||||
use types::view;
|
||||
use types::views::BlockView;
|
||||
|
||||
use client::{BlockChainClient, Client, ClientConfig, BlockId, ChainInfo, BlockInfo, PrepareOpenBlock, ImportSealedBlock, ImportBlock};
|
||||
use client::{BlockChainClient, BlockChainReset, Client, ClientConfig, BlockId, ChainInfo, BlockInfo, PrepareOpenBlock, ImportSealedBlock, ImportBlock};
|
||||
use ethereum;
|
||||
use executive::{Executive, TransactOptions};
|
||||
use miner::{Miner, PendingOrdering, MinerService};
|
||||
@@ -366,3 +366,23 @@ fn transaction_proof() {
|
||||
assert_eq!(state.balance(&Address::default()).unwrap(), 5.into());
|
||||
assert_eq!(state.balance(&address).unwrap(), 95.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset_blockchain() {
|
||||
let client = get_test_client_with_blocks(get_good_dummy_block_seq(19));
|
||||
// 19 + genesis block
|
||||
assert!(client.block_header(BlockId::Number(20)).is_some());
|
||||
assert_eq!(client.block_header(BlockId::Number(20)).unwrap().hash(), client.best_block_header().hash());
|
||||
|
||||
assert!(client.reset(5).is_ok());
|
||||
|
||||
client.chain().clear_cache();
|
||||
|
||||
assert!(client.block_header(BlockId::Number(20)).is_none());
|
||||
assert!(client.block_header(BlockId::Number(19)).is_none());
|
||||
assert!(client.block_header(BlockId::Number(18)).is_none());
|
||||
assert!(client.block_header(BlockId::Number(17)).is_none());
|
||||
assert!(client.block_header(BlockId::Number(16)).is_none());
|
||||
|
||||
assert!(client.block_header(BlockId::Number(15)).is_some());
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ use types::{BlockNumber, header::Header};
|
||||
use types::transaction::SignedTransaction;
|
||||
use verification::queue::kind::blocks::Unverified;
|
||||
|
||||
#[cfg(not(time_checked_add))]
|
||||
use time_utils::CheckedSystemTime;
|
||||
|
||||
/// Preprocessed block data gathered in `verify_block_unordered` call
|
||||
@@ -310,7 +309,7 @@ pub fn verify_header_params(header: &Header, engine: &EthEngine, is_full: bool,
|
||||
// this will resist overflow until `year 2037`
|
||||
let max_time = SystemTime::now() + ACCEPTABLE_DRIFT;
|
||||
let invalid_threshold = max_time + ACCEPTABLE_DRIFT * 9;
|
||||
let timestamp = UNIX_EPOCH.checked_add(Duration::from_secs(header.timestamp()))
|
||||
let timestamp = CheckedSystemTime::checked_add(UNIX_EPOCH, Duration::from_secs(header.timestamp()))
|
||||
.ok_or(BlockError::TimestampOverflow)?;
|
||||
|
||||
if timestamp > invalid_threshold {
|
||||
@@ -334,9 +333,9 @@ fn verify_parent(header: &Header, parent: &Header, engine: &EthEngine) -> Result
|
||||
|
||||
if !engine.is_timestamp_valid(header.timestamp(), parent.timestamp()) {
|
||||
let now = SystemTime::now();
|
||||
let min = now.checked_add(Duration::from_secs(parent.timestamp().saturating_add(1)))
|
||||
let min = CheckedSystemTime::checked_add(now, Duration::from_secs(parent.timestamp().saturating_add(1)))
|
||||
.ok_or(BlockError::TimestampOverflow)?;
|
||||
let found = now.checked_add(Duration::from_secs(header.timestamp()))
|
||||
let found = CheckedSystemTime::checked_add(now, Duration::from_secs(header.timestamp()))
|
||||
.ok_or(BlockError::TimestampOverflow)?;
|
||||
return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: None, min: Some(min), found })))
|
||||
}
|
||||
|
||||
@@ -122,6 +122,8 @@ impl SnapshotService for TestSnapshotService {
|
||||
self.block_restoration_chunks.lock().clear();
|
||||
}
|
||||
|
||||
fn abort_snapshot(&self) {}
|
||||
|
||||
fn restore_state_chunk(&self, hash: H256, chunk: Bytes) {
|
||||
if self.restoration_manifest.lock().as_ref().map_or(false, |m| m.state_hashes.iter().any(|h| h == &hash)) {
|
||||
self.state_restoration_chunks.lock().insert(hash, chunk);
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
//! Block header.
|
||||
|
||||
use std::cmp;
|
||||
use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP, keccak};
|
||||
use heapsize::HeapSizeOf;
|
||||
use ethereum_types::{H256, U256, Address, Bloom};
|
||||
@@ -342,7 +341,7 @@ impl Decodable for Header {
|
||||
number: r.val_at(8)?,
|
||||
gas_limit: r.val_at(9)?,
|
||||
gas_used: r.val_at(10)?,
|
||||
timestamp: cmp::min(r.val_at::<U256>(11)?, u64::max_value().into()).as_u64(),
|
||||
timestamp: r.val_at(11)?,
|
||||
extra_data: r.val_at(12)?,
|
||||
seal: vec![],
|
||||
hash: keccak(r.as_raw()).into(),
|
||||
@@ -412,4 +411,15 @@ mod tests {
|
||||
|
||||
assert_eq!(header_rlp, encoded_header);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reject_header_with_large_timestamp() {
|
||||
// that's rlp of block header created with ethash engine.
|
||||
// The encoding contains a large timestamp (295147905179352825856)
|
||||
let header_rlp = "f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d891000000000000000000080a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23".from_hex().unwrap();
|
||||
|
||||
// This should fail decoding timestamp
|
||||
let header: Result<Header, _> = rlp::decode(&header_rlp);
|
||||
assert_eq!(header.unwrap_err(), rlp::DecoderError::RlpIsTooBig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -932,7 +932,7 @@ impl Configuration {
|
||||
no_periodic: self.args.flag_no_periodic_snapshot,
|
||||
processing_threads: match self.args.arg_snapshot_threads {
|
||||
Some(threads) if threads > 0 => threads,
|
||||
_ => ::std::cmp::max(1, num_cpus::get() / 2),
|
||||
_ => ::std::cmp::max(1, num_cpus::get_physical() / 2),
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Ethcore client application.
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
extern crate ansi_term;
|
||||
|
||||
@@ -17,7 +17,5 @@
|
||||
//! Utilities and helpers for the light client.
|
||||
|
||||
mod epoch_fetch;
|
||||
mod queue_cull;
|
||||
|
||||
pub use self::epoch_fetch::EpochFetch;
|
||||
pub use self::queue_cull::QueueCull;
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Ethereum.
|
||||
|
||||
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Service for culling the light client's transaction queue.
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use ethcore::client::ClientIoMessage;
|
||||
use sync::{LightSync, LightNetworkDispatcher};
|
||||
use io::{IoContext, IoHandler, TimerToken};
|
||||
|
||||
use light::client::LightChainClient;
|
||||
use light::on_demand::{request, OnDemand, OnDemandRequester};
|
||||
use light::TransactionQueue;
|
||||
|
||||
use futures::{future, Future};
|
||||
|
||||
use parity_runtime::Executor;
|
||||
|
||||
use parking_lot::RwLock;
|
||||
|
||||
// Attepmt to cull once every 10 minutes.
|
||||
const TOKEN: TimerToken = 1;
|
||||
const TIMEOUT: Duration = Duration::from_secs(60 * 10);
|
||||
|
||||
// But make each attempt last only 9 minutes
|
||||
const PURGE_TIMEOUT: Duration = Duration::from_secs(60 * 9);
|
||||
|
||||
/// Periodically culls the transaction queue of mined transactions.
|
||||
pub struct QueueCull<T> {
|
||||
/// A handle to the client, for getting the latest block header.
|
||||
pub client: Arc<T>,
|
||||
/// A handle to the sync service.
|
||||
pub sync: Arc<LightSync>,
|
||||
/// The on-demand request service.
|
||||
pub on_demand: Arc<OnDemand>,
|
||||
/// The transaction queue.
|
||||
pub txq: Arc<RwLock<TransactionQueue>>,
|
||||
/// Event loop executor.
|
||||
pub executor: Executor,
|
||||
}
|
||||
|
||||
impl<T: LightChainClient + 'static> IoHandler<ClientIoMessage> for QueueCull<T> {
|
||||
fn initialize(&self, io: &IoContext<ClientIoMessage>) {
|
||||
io.register_timer(TOKEN, TIMEOUT).expect("Error registering timer");
|
||||
}
|
||||
|
||||
fn timeout(&self, _io: &IoContext<ClientIoMessage>, timer: TimerToken) {
|
||||
if timer != TOKEN { return }
|
||||
|
||||
let senders = self.txq.read().queued_senders();
|
||||
if senders.is_empty() { return }
|
||||
|
||||
let (sync, on_demand, txq) = (self.sync.clone(), self.on_demand.clone(), self.txq.clone());
|
||||
let best_header = self.client.best_block_header();
|
||||
let start_nonce = self.client.engine().account_start_nonce(best_header.number());
|
||||
|
||||
info!(target: "cull", "Attempting to cull queued transactions from {} senders.", senders.len());
|
||||
self.executor.spawn_with_timeout(move || {
|
||||
let maybe_fetching = sync.with_context(move |ctx| {
|
||||
// fetch the nonce of each sender in the queue.
|
||||
let nonce_reqs = senders.iter()
|
||||
.map(|&address| request::Account { header: best_header.clone().into(), address: address })
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// when they come in, update each sender to the new nonce.
|
||||
on_demand.request(ctx, nonce_reqs)
|
||||
.expect("No back-references; therefore all back-references are valid; qed")
|
||||
.map(move |accs| {
|
||||
let txq = txq.write();
|
||||
let _ = accs.into_iter()
|
||||
.map(|maybe_acc| maybe_acc.map_or(start_nonce, |acc| acc.nonce))
|
||||
.zip(senders)
|
||||
.fold(txq, |mut txq, (nonce, addr)| {
|
||||
txq.cull(addr, nonce);
|
||||
txq
|
||||
});
|
||||
})
|
||||
.map_err(|_| debug!(target: "cull", "OnDemand prematurely closed channel."))
|
||||
});
|
||||
|
||||
match maybe_fetching {
|
||||
Some(fut) => future::Either::A(fut),
|
||||
None => {
|
||||
debug!(target: "cull", "Unable to acquire network context; qed");
|
||||
future::Either::B(future::ok(()))
|
||||
},
|
||||
}
|
||||
}, PURGE_TIMEOUT, || {})
|
||||
}
|
||||
}
|
||||
@@ -252,6 +252,7 @@ pub struct FullDependencies {
|
||||
pub gas_price_percentile: usize,
|
||||
pub poll_lifetime: u32,
|
||||
pub allow_missing_blocks: bool,
|
||||
pub no_ancient_blocks: bool,
|
||||
}
|
||||
|
||||
impl FullDependencies {
|
||||
@@ -303,6 +304,7 @@ impl FullDependencies {
|
||||
gas_price_percentile: self.gas_price_percentile,
|
||||
allow_missing_blocks: self.allow_missing_blocks,
|
||||
allow_experimental_rpcs: self.experimental_rpcs,
|
||||
no_ancient_blocks: self.no_ancient_blocks
|
||||
}
|
||||
);
|
||||
handler.extend_with(client.to_delegate());
|
||||
|
||||
@@ -295,17 +295,6 @@ fn execute_light_impl<Cr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq
|
||||
// spin up event loop
|
||||
let runtime = Runtime::with_default_thread_count();
|
||||
|
||||
// queue cull service.
|
||||
let queue_cull = Arc::new(::light_helpers::QueueCull {
|
||||
client: client.clone(),
|
||||
sync: light_sync.clone(),
|
||||
on_demand: on_demand.clone(),
|
||||
txq: txq.clone(),
|
||||
executor: runtime.executor(),
|
||||
});
|
||||
|
||||
service.register_handler(queue_cull).map_err(|e| format!("Error attaching service: {:?}", e))?;
|
||||
|
||||
// start the network.
|
||||
light_sync.start_network();
|
||||
|
||||
@@ -753,6 +742,7 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
|
||||
gas_price_percentile: cmd.gas_price_percentile,
|
||||
poll_lifetime: cmd.poll_lifetime,
|
||||
allow_missing_blocks: cmd.allow_missing_blocks,
|
||||
no_ancient_blocks: !cmd.download_old_blocks,
|
||||
});
|
||||
|
||||
let dependencies = rpc::Dependencies {
|
||||
@@ -903,17 +893,27 @@ impl RunningClient {
|
||||
// Create a weak reference to the client so that we can wait on shutdown
|
||||
// until it is dropped
|
||||
let weak_client = Arc::downgrade(&client);
|
||||
// Shutdown and drop the ServiceClient
|
||||
// Shutdown and drop the ClientService
|
||||
client_service.shutdown();
|
||||
trace!(target: "shutdown", "ClientService shut down");
|
||||
drop(client_service);
|
||||
trace!(target: "shutdown", "ClientService dropped");
|
||||
// drop this stuff as soon as exit detected.
|
||||
drop(rpc);
|
||||
trace!(target: "shutdown", "RPC dropped");
|
||||
drop(keep_alive);
|
||||
trace!(target: "shutdown", "KeepAlive dropped");
|
||||
// to make sure timer does not spawn requests while shutdown is in progress
|
||||
informant.shutdown();
|
||||
trace!(target: "shutdown", "Informant shut down");
|
||||
// just Arc is dropping here, to allow other reference release in its default time
|
||||
drop(informant);
|
||||
trace!(target: "shutdown", "Informant dropped");
|
||||
drop(client);
|
||||
trace!(target: "shutdown", "Client dropped");
|
||||
// This may help when debugging ref cycles. Requires nightly-only `#![feature(weak_counts)]`
|
||||
// trace!(target: "shutdown", "Waiting for refs to Client to shutdown, strong_count={:?}, weak_count={:?}", weak_client.strong_count(), weak_client.weak_count());
|
||||
trace!(target: "shutdown", "Waiting for refs to Client to shutdown");
|
||||
wait_for_drop(weak_client);
|
||||
}
|
||||
}
|
||||
@@ -947,24 +947,30 @@ fn print_running_environment(data_dir: &str, dirs: &Directories, db_dirs: &Datab
|
||||
}
|
||||
|
||||
fn wait_for_drop<T>(w: Weak<T>) {
|
||||
let sleep_duration = Duration::from_secs(1);
|
||||
let warn_timeout = Duration::from_secs(60);
|
||||
let max_timeout = Duration::from_secs(300);
|
||||
const SLEEP_DURATION: Duration = Duration::from_secs(1);
|
||||
const WARN_TIMEOUT: Duration = Duration::from_secs(60);
|
||||
const MAX_TIMEOUT: Duration = Duration::from_secs(300);
|
||||
|
||||
let instant = Instant::now();
|
||||
let mut warned = false;
|
||||
|
||||
while instant.elapsed() < max_timeout {
|
||||
while instant.elapsed() < MAX_TIMEOUT {
|
||||
if w.upgrade().is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
if !warned && instant.elapsed() > warn_timeout {
|
||||
if !warned && instant.elapsed() > WARN_TIMEOUT {
|
||||
warned = true;
|
||||
warn!("Shutdown is taking longer than expected.");
|
||||
}
|
||||
|
||||
thread::sleep(sleep_duration);
|
||||
thread::sleep(SLEEP_DURATION);
|
||||
|
||||
// When debugging shutdown issues on a nightly build it can help to enable this with the
|
||||
// `#![feature(weak_counts)]` added to lib.rs (TODO: enable when
|
||||
// https://github.com/rust-lang/rust/issues/57977 is stable)
|
||||
// trace!(target: "shutdown", "Waiting for client to drop, strong_count={:?}, weak_count={:?}", w.strong_count(), w.weak_count());
|
||||
trace!(target: "shutdown", "Waiting for client to drop");
|
||||
}
|
||||
|
||||
warn!("Shutdown timeout reached, exiting uncleanly.");
|
||||
|
||||
@@ -261,7 +261,7 @@ impl SnapshotCommand {
|
||||
let cur_size = p.size();
|
||||
if cur_size != last_size {
|
||||
last_size = cur_size;
|
||||
let bytes = ::informant::format_bytes(p.size());
|
||||
let bytes = ::informant::format_bytes(cur_size as usize);
|
||||
info!("Snapshot: {} accounts {} blocks {}", p.accounts(), p.blocks(), bytes);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ use light::on_demand::error::{Error as OnDemandError, ErrorKind as OnDemandError
|
||||
use ethcore::client::BlockChainClient;
|
||||
use types::blockchain_info::BlockChainInfo;
|
||||
use v1::types::BlockNumber;
|
||||
use v1::impls::EthClientOptions;
|
||||
|
||||
mod codes {
|
||||
// NOTE [ToDr] Codes from [-32099, -32000]
|
||||
@@ -221,18 +222,34 @@ pub fn cannot_submit_work(err: EthcoreError) -> Error {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unavailable_block() -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
|
||||
message: "Ancient block sync is still in progress".into(),
|
||||
data: None,
|
||||
pub fn unavailable_block(no_ancient_block: bool, by_hash: bool) -> Error {
|
||||
if no_ancient_block {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
|
||||
message: "Looks like you disabled ancient block download, unfortunately the information you're \
|
||||
trying to fetch doesn't exist in the db and is probably in the ancient blocks.".into(),
|
||||
data: None,
|
||||
}
|
||||
} else if by_hash {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
|
||||
message: "Block information is incomplete while ancient block sync is still in progress, before \
|
||||
it's finished we can't determine the existence of requested item.".into(),
|
||||
data: None,
|
||||
}
|
||||
} else {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
|
||||
message: "Requested block number is in a range that is not available yet, because the ancient block sync is still in progress.".into(),
|
||||
data: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_block_number_existence<'a, T, C>(
|
||||
client: &'a C,
|
||||
num: BlockNumber,
|
||||
allow_missing_blocks: bool,
|
||||
options: EthClientOptions,
|
||||
) ->
|
||||
impl Fn(Option<T>) -> RpcResult<Option<T>> + 'a
|
||||
where C: BlockChainClient,
|
||||
@@ -242,8 +259,8 @@ pub fn check_block_number_existence<'a, T, C>(
|
||||
if let BlockNumber::Num(block_number) = num {
|
||||
// tried to fetch block number and got nothing even though the block number is
|
||||
// less than the latest block number
|
||||
if block_number < client.chain_info().best_block_number && !allow_missing_blocks {
|
||||
return Err(unavailable_block());
|
||||
if block_number < client.chain_info().best_block_number && !options.allow_missing_blocks {
|
||||
return Err(unavailable_block(options.no_ancient_blocks, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -253,22 +270,17 @@ pub fn check_block_number_existence<'a, T, C>(
|
||||
|
||||
pub fn check_block_gap<'a, T, C>(
|
||||
client: &'a C,
|
||||
allow_missing_blocks: bool,
|
||||
options: EthClientOptions,
|
||||
) -> impl Fn(Option<T>) -> RpcResult<Option<T>> + 'a
|
||||
where C: BlockChainClient,
|
||||
{
|
||||
move |response| {
|
||||
if response.is_none() && !allow_missing_blocks {
|
||||
if response.is_none() && !options.allow_missing_blocks {
|
||||
let BlockChainInfo { ancient_block_hash, .. } = client.chain_info();
|
||||
// block information was requested, but unfortunately we couldn't find it and there
|
||||
// are gaps in the database ethcore/src/blockchain/blockchain.rs
|
||||
if ancient_block_hash.is_some() {
|
||||
return Err(Error {
|
||||
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
|
||||
message: "Block information is incomplete while ancient block sync is still in progress, before \
|
||||
it's finished we can't determine the existence of requested item.".into(),
|
||||
data: None,
|
||||
})
|
||||
return Err(unavailable_block(options.no_ancient_blocks, true))
|
||||
}
|
||||
}
|
||||
Ok(response)
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
|
||||
//! Helpers for fetching blockchain data either from the light client or the network.
|
||||
|
||||
use std::cmp;
|
||||
use std::clone::Clone;
|
||||
use std::cmp;
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use types::basic_account::BasicAccount;
|
||||
@@ -48,7 +49,6 @@ use ethereum_types::{Address, U256};
|
||||
use hash::H256;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use fastmap::H256FastMap;
|
||||
use std::collections::BTreeMap;
|
||||
use types::transaction::{Action, Transaction as EthTransaction, PendingTransaction, SignedTransaction, LocalizedTransaction};
|
||||
|
||||
use v1::helpers::{CallRequest as CallRequestHelper, errors, dispatch};
|
||||
@@ -523,6 +523,46 @@ where
|
||||
}))
|
||||
}
|
||||
|
||||
/// Helper to cull the `light` transaction queue of mined transactions
|
||||
pub fn light_cull(&self, txq: Arc<RwLock<TransactionQueue>>) -> impl Future <Item = (), Error = Error> + Send {
|
||||
let senders = txq.read().queued_senders();
|
||||
if senders.is_empty() {
|
||||
return Either::B(future::err(errors::internal("No pending local transactions", "")));
|
||||
}
|
||||
|
||||
let sync = self.sync.clone();
|
||||
let on_demand = self.on_demand.clone();
|
||||
let best_header = self.client.best_block_header();
|
||||
let start_nonce = self.client.engine().account_start_nonce(best_header.number());
|
||||
|
||||
let account_request = sync.with_context(move |ctx| {
|
||||
// fetch the nonce of each sender in the queue.
|
||||
let nonce_reqs = senders.iter()
|
||||
.map(|&address| request::Account { header: best_header.clone().into(), address })
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// when they come in, update each sender to the new nonce.
|
||||
on_demand.request(ctx, nonce_reqs)
|
||||
.expect(NO_INVALID_BACK_REFS_PROOF)
|
||||
.map(move |accs| {
|
||||
let mut txq = txq.write();
|
||||
accs.into_iter()
|
||||
.map(|maybe_acc| maybe_acc.map_or(start_nonce, |acc| acc.nonce))
|
||||
.zip(senders)
|
||||
.for_each(|(nonce, addr)| {
|
||||
txq.cull(addr, nonce);
|
||||
});
|
||||
})
|
||||
.map_err(errors::on_demand_error)
|
||||
});
|
||||
|
||||
if let Some(fut) = account_request {
|
||||
Either::A(fut)
|
||||
} else {
|
||||
Either::B(future::err(errors::network_disabled()))
|
||||
}
|
||||
}
|
||||
|
||||
fn send_requests<T, F>(&self, reqs: Vec<OnDemandRequest>, parse_response: F) -> impl Future<Item = T, Error = Error> + Send where
|
||||
F: FnOnce(Vec<OnDemandResponse>) -> T + Send + 'static,
|
||||
T: Send + 'static,
|
||||
|
||||
@@ -54,6 +54,7 @@ use v1::metadata::Metadata;
|
||||
const EXTRA_INFO_PROOF: &str = "Object exists in blockchain (fetched earlier), extra_info is always available if object exists; qed";
|
||||
|
||||
/// Eth RPC options
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct EthClientOptions {
|
||||
/// Return nonce from transaction queue when pending block not available.
|
||||
pub pending_nonce_from_queue: bool,
|
||||
@@ -68,6 +69,8 @@ pub struct EthClientOptions {
|
||||
pub allow_missing_blocks: bool,
|
||||
/// Enable Experimental RPC-Calls
|
||||
pub allow_experimental_rpcs: bool,
|
||||
/// flag for ancient block sync
|
||||
pub no_ancient_blocks: bool,
|
||||
}
|
||||
|
||||
impl EthClientOptions {
|
||||
@@ -89,6 +92,7 @@ impl Default for EthClientOptions {
|
||||
gas_price_percentile: 50,
|
||||
allow_missing_blocks: false,
|
||||
allow_experimental_rpcs: false,
|
||||
no_ancient_blocks: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -669,7 +673,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
|
||||
let trx_count = self.client.block(BlockId::Hash(hash))
|
||||
.map(|block| block.transactions_count().into());
|
||||
let result = Ok(trx_count)
|
||||
.and_then(errors::check_block_gap(&*self.client, self.options.allow_missing_blocks));
|
||||
.and_then(errors::check_block_gap(&*self.client, self.options));
|
||||
Box::new(future::done(result))
|
||||
}
|
||||
|
||||
@@ -684,7 +688,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
|
||||
.and_then(errors::check_block_number_existence(
|
||||
&*self.client,
|
||||
num,
|
||||
self.options.allow_missing_blocks
|
||||
self.options
|
||||
))
|
||||
}
|
||||
}))
|
||||
@@ -694,7 +698,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
|
||||
let uncle_count = self.client.block(BlockId::Hash(hash))
|
||||
.map(|block| block.uncles_count().into());
|
||||
let result = Ok(uncle_count)
|
||||
.and_then(errors::check_block_gap(&*self.client, self.options.allow_missing_blocks));
|
||||
.and_then(errors::check_block_gap(&*self.client, self.options));
|
||||
Box::new(future::done(result))
|
||||
}
|
||||
|
||||
@@ -708,7 +712,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
|
||||
.and_then(errors::check_block_number_existence(
|
||||
&*self.client,
|
||||
num,
|
||||
self.options.allow_missing_blocks
|
||||
self.options
|
||||
))
|
||||
}
|
||||
}))
|
||||
@@ -730,13 +734,13 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
|
||||
|
||||
fn block_by_hash(&self, hash: H256, include_txs: bool) -> BoxFuture<Option<RichBlock>> {
|
||||
let result = self.rich_block(BlockId::Hash(hash).into(), include_txs)
|
||||
.and_then(errors::check_block_gap(&*self.client, self.options.allow_missing_blocks));
|
||||
.and_then(errors::check_block_gap(&*self.client, self.options));
|
||||
Box::new(future::done(result))
|
||||
}
|
||||
|
||||
fn block_by_number(&self, num: BlockNumber, include_txs: bool) -> BoxFuture<Option<RichBlock>> {
|
||||
let result = self.rich_block(num.clone().into(), include_txs).and_then(
|
||||
errors::check_block_number_existence(&*self.client, num, self.options.allow_missing_blocks));
|
||||
errors::check_block_number_existence(&*self.client, num, self.options));
|
||||
Box::new(future::done(result))
|
||||
}
|
||||
|
||||
@@ -746,14 +750,14 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
|
||||
.map(|t| Transaction::from_pending(t.pending().clone()))
|
||||
});
|
||||
let result = Ok(tx).and_then(
|
||||
errors::check_block_gap(&*self.client, self.options.allow_missing_blocks));
|
||||
errors::check_block_gap(&*self.client, self.options));
|
||||
Box::new(future::done(result))
|
||||
}
|
||||
|
||||
fn transaction_by_block_hash_and_index(&self, hash: H256, index: Index) -> BoxFuture<Option<Transaction>> {
|
||||
let id = PendingTransactionId::Location(PendingOrBlock::Block(BlockId::Hash(hash)), index.value());
|
||||
let result = self.transaction(id).and_then(
|
||||
errors::check_block_gap(&*self.client, self.options.allow_missing_blocks));
|
||||
errors::check_block_gap(&*self.client, self.options));
|
||||
Box::new(future::done(result))
|
||||
}
|
||||
|
||||
@@ -767,7 +771,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
|
||||
|
||||
let transaction_id = PendingTransactionId::Location(block_id, index.value());
|
||||
let result = self.transaction(transaction_id).and_then(
|
||||
errors::check_block_number_existence(&*self.client, num, self.options.allow_missing_blocks));
|
||||
errors::check_block_number_existence(&*self.client, num, self.options));
|
||||
Box::new(future::done(result))
|
||||
}
|
||||
|
||||
@@ -781,7 +785,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
|
||||
|
||||
let receipt = self.client.transaction_receipt(TransactionId::Hash(hash));
|
||||
let result = Ok(receipt.map(Into::into))
|
||||
.and_then(errors::check_block_gap(&*self.client, self.options.allow_missing_blocks));
|
||||
.and_then(errors::check_block_gap(&*self.client, self.options));
|
||||
Box::new(future::done(result))
|
||||
}
|
||||
|
||||
@@ -789,7 +793,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
|
||||
let result = self.uncle(PendingUncleId {
|
||||
id: PendingOrBlock::Block(BlockId::Hash(hash)),
|
||||
position: index.value()
|
||||
}).and_then(errors::check_block_gap(&*self.client, self.options.allow_missing_blocks));
|
||||
}).and_then(errors::check_block_gap(&*self.client, self.options));
|
||||
Box::new(future::done(result))
|
||||
}
|
||||
|
||||
@@ -806,7 +810,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
|
||||
.and_then(errors::check_block_number_existence(
|
||||
&*self.client,
|
||||
num,
|
||||
self.options.allow_missing_blocks
|
||||
self.options
|
||||
));
|
||||
|
||||
Box::new(future::done(result))
|
||||
|
||||
@@ -420,15 +420,22 @@ where
|
||||
}
|
||||
|
||||
fn transaction_by_hash(&self, hash: H256) -> BoxFuture<Option<Transaction>> {
|
||||
{
|
||||
let tx_queue = self.transaction_queue.read();
|
||||
if let Some(tx) = tx_queue.get(&hash) {
|
||||
let in_txqueue = self.transaction_queue.read().get(&hash).is_some();
|
||||
|
||||
// The transaction is in the `local txqueue` then fetch the latest state from the network and attempt
|
||||
// to cull the transaction queue.
|
||||
if in_txqueue {
|
||||
// Note, this will block (relies on HTTP timeout) to make sure `cull` will finish to avoid having to call
|
||||
// `eth_getTransactionByHash` more than once to ensure the `txqueue` is up to `date` when it is called
|
||||
if let Err(e) = self.fetcher().light_cull(self.transaction_queue.clone()).wait() {
|
||||
debug!(target: "cull", "failed because of: {:?}", e);
|
||||
}
|
||||
if let Some(tx) = self.transaction_queue.read().get(&hash) {
|
||||
return Box::new(future::ok(Some(Transaction::from_pending(
|
||||
tx.clone(),
|
||||
))));
|
||||
}
|
||||
}
|
||||
|
||||
Box::new(self.fetcher().transaction_by_hash(hash).map(|x| x.map(|(tx, _)| tx)))
|
||||
}
|
||||
|
||||
|
||||
@@ -143,7 +143,8 @@ impl EthTester {
|
||||
send_block_number_in_get_work: true,
|
||||
gas_price_percentile: 50,
|
||||
allow_experimental_rpcs: true,
|
||||
allow_missing_blocks: false
|
||||
allow_missing_blocks: false,
|
||||
no_ancient_blocks: false
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ impl SnapshotService for TestSnapshotService {
|
||||
fn status(&self) -> RestorationStatus { self.status.lock().clone() }
|
||||
fn begin_restore(&self, _manifest: ManifestData) { }
|
||||
fn abort_restore(&self) { }
|
||||
fn abort_snapshot(&self) {}
|
||||
fn restore_state_chunk(&self, _hash: H256, _chunk: Bytes) { }
|
||||
fn restore_block_chunk(&self, _hash: H256, _chunk: Bytes) { }
|
||||
fn shutdown(&self) { }
|
||||
|
||||
@@ -1,30 +1,48 @@
|
||||
FROM ubuntu:xenial
|
||||
LABEL MAINTAINER="Parity Technologies <devops-team@parity.io>"
|
||||
|
||||
# install tools and dependencies
|
||||
RUN apt update && apt install -y --no-install-recommends openssl libudev-dev file curl jq
|
||||
# metadata
|
||||
ARG VCS_REF
|
||||
ARG BUILD_DATE
|
||||
|
||||
LABEL io.parity.image.authors="devops-team@parity.io" \
|
||||
io.parity.image.vendor="Parity Technologies" \
|
||||
io.parity.image.title="parity/parity" \
|
||||
io.parity.image.description="Parity Ethereum. The Fastest and most Advanced Ethereum Client." \
|
||||
io.parity.image.source="https://github.com/paritytech/parity-ethereum/blob/${VCS_REF}/\
|
||||
scripts/docker/hub/Dockerfile" \
|
||||
io.parity.image.documentation="https://wiki.parity.io/Parity-Ethereum" \
|
||||
io.parity.image.revision="${VCS_REF}" \
|
||||
io.parity.image.created="${BUILD_DATE}"
|
||||
|
||||
# show backtraces
|
||||
ENV RUST_BACKTRACE 1
|
||||
|
||||
# cleanup Docker image
|
||||
RUN apt autoremove -y \
|
||||
&& apt clean -y \
|
||||
&& rm -rf /tmp/* /var/tmp/* /var/lib/apt/lists/*
|
||||
|
||||
RUN groupadd -g 1000 parity \
|
||||
&& useradd -m -u 1000 -g parity -s /bin/sh parity
|
||||
# install tools and dependencies
|
||||
RUN set -eux; \
|
||||
apt-get update; \
|
||||
apt-get install -y --no-install-recommends \
|
||||
file curl jq; \
|
||||
# apt cleanup
|
||||
apt-get autoremove -y; \
|
||||
apt-get clean; \
|
||||
rm -rf /tmp/* /var/tmp/* /var/lib/apt/lists/*; \
|
||||
# add user
|
||||
groupadd -g 1000 parity; \
|
||||
useradd -m -u 1000 -g parity -s /bin/sh parity
|
||||
|
||||
WORKDIR /home/parity
|
||||
|
||||
# add parity-ethereum to docker image
|
||||
# add parity-ethereum binary to docker image
|
||||
COPY artifacts/x86_64-unknown-linux-gnu/parity /bin/parity
|
||||
|
||||
COPY scripts/docker/hub/check_sync.sh /check_sync.sh
|
||||
COPY tools/check_sync.sh /check_sync.sh
|
||||
|
||||
# switch to user parity here
|
||||
USER parity
|
||||
|
||||
# check if executable works in this container
|
||||
RUN parity --version
|
||||
|
||||
EXPOSE 5001 8080 8082 8083 8545 8546 8180 30303/tcp 30303/udp
|
||||
|
||||
ENTRYPOINT ["/bin/parity"]
|
||||
|
||||
|
||||
67
scripts/docker/hub/publish-docker.sh
Executable file
67
scripts/docker/hub/publish-docker.sh
Executable file
@@ -0,0 +1,67 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e # fail on any error
|
||||
|
||||
VERSION=$(cat ./tools/VERSION)
|
||||
TRACK=$(cat ./tools/TRACK)
|
||||
echo "Parity Ethereum version = ${VERSION}"
|
||||
echo "Parity Ethereum track = ${TRACK}"
|
||||
|
||||
test "$Docker_Hub_User_Parity" -a "$Docker_Hub_Pass_Parity" \
|
||||
|| ( echo "no docker credentials provided"; exit 1 )
|
||||
docker login -u "$Docker_Hub_User_Parity" -p "$Docker_Hub_Pass_Parity"
|
||||
echo "__________Docker info__________"
|
||||
docker info
|
||||
|
||||
# we stopped pushing nightlies to dockerhub, will push to own registry prb.
|
||||
case "${SCHEDULE_TAG:-${CI_COMMIT_REF_NAME}}" in
|
||||
"$SCHEDULE_TAG")
|
||||
echo "Docker TAG - 'parity/parity:${SCHEDULE_TAG}'";
|
||||
docker build --no-cache \
|
||||
--build-arg VCS_REF="${CI_COMMIT_SHA}" \
|
||||
--build-arg BUILD_DATE="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" \
|
||||
--tag "parity/parity:${SCHEDULE_TAG}" \
|
||||
--file tools/Dockerfile .;
|
||||
docker push "parity/parity:${SCHEDULE_TAG}";;
|
||||
"beta")
|
||||
echo "Docker TAGs - 'parity/parity:beta', 'parity/parity:latest', \
|
||||
'parity/parity:${VERSION}-${CI_COMMIT_REF_NAME}'";
|
||||
docker build --no-cache \
|
||||
--build-arg VCS_REF="${CI_COMMIT_SHA}" \
|
||||
--build-arg BUILD_DATE="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" \
|
||||
--tag "parity/parity:beta" \
|
||||
--tag "parity/parity:latest" \
|
||||
--tag "parity/parity:${VERSION}-${CI_COMMIT_REF_NAME}" \
|
||||
--file tools/Dockerfile .;
|
||||
docker push "parity/parity:beta";
|
||||
docker push "parity/parity:latest";
|
||||
docker push "parity/parity:${VERSION}-${CI_COMMIT_REF_NAME}";;
|
||||
"stable")
|
||||
echo "Docker TAGs - 'parity/parity:${VERSION}-${CI_COMMIT_REF_NAME}', 'parity/parity:stable'";
|
||||
docker build --no-cache \
|
||||
--build-arg VCS_REF="${CI_COMMIT_SHA}" \
|
||||
--build-arg BUILD_DATE="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" \
|
||||
--tag "parity/parity:${VERSION}-${CI_COMMIT_REF_NAME}" \
|
||||
--tag "parity/parity:stable" \
|
||||
--file tools/Dockerfile .;
|
||||
docker push "parity/parity:${VERSION}-${CI_COMMIT_REF_NAME}";
|
||||
docker push "parity/parity:stable";;
|
||||
v[0-9]*.[0-9]*)
|
||||
echo "Docker TAG - 'parity/parity:${VERSION}-${TRACK}'"
|
||||
docker build --no-cache \
|
||||
--build-arg VCS_REF="${CI_COMMIT_SHA}" \
|
||||
--build-arg BUILD_DATE="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" \
|
||||
--tag "parity/parity:${VERSION}-${TRACK}" \
|
||||
--file tools/Dockerfile .;
|
||||
docker push "parity/parity:${VERSION}-${TRACK}";;
|
||||
*)
|
||||
echo "Docker TAG - 'parity/parity:${VERSION}-${CI_COMMIT_REF_NAME}'"
|
||||
docker build --no-cache \
|
||||
--build-arg VCS_REF="${CI_COMMIT_SHA}" \
|
||||
--build-arg BUILD_DATE="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" \
|
||||
--tag "parity/parity:${VERSION}-${CI_COMMIT_REF_NAME}" \
|
||||
--file tools/Dockerfile .;
|
||||
docker push "parity/parity:${VERSION}-${CI_COMMIT_REF_NAME}";;
|
||||
esac
|
||||
|
||||
docker logout
|
||||
@@ -18,13 +18,13 @@ cat .cargo/config
|
||||
echo "_____ Building target: "$CARGO_TARGET" _____"
|
||||
if [ "${CARGO_TARGET}" = "armv7-linux-androideabi" ]
|
||||
then
|
||||
time cargo build --target $CARGO_TARGET --release -p parity-clib --features final
|
||||
time cargo build --target $CARGO_TARGET --verbose --color=always --release -p parity-clib --features final
|
||||
else
|
||||
time cargo build --target $CARGO_TARGET --release --features final
|
||||
time cargo build --target $CARGO_TARGET --release -p evmbin
|
||||
time cargo build --target $CARGO_TARGET --release -p ethstore-cli
|
||||
time cargo build --target $CARGO_TARGET --release -p ethkey-cli
|
||||
time cargo build --target $CARGO_TARGET --release -p whisper-cli
|
||||
time cargo build --target $CARGO_TARGET --verbose --color=always --release --features final
|
||||
time cargo build --target $CARGO_TARGET --verbose --color=always --release -p evmbin
|
||||
time cargo build --target $CARGO_TARGET --verbose --color=always --release -p ethstore-cli
|
||||
time cargo build --target $CARGO_TARGET --verbose --color=always --release -p ethkey-cli
|
||||
time cargo build --target $CARGO_TARGET --verbose --color=always --release -p whisper-cli
|
||||
fi
|
||||
|
||||
echo "_____ Post-processing binaries _____"
|
||||
|
||||
@@ -14,11 +14,11 @@ echo "RUSTC_WRAPPER: " $RUSTC_WRAPPER
|
||||
echo "SCCACHE_DIR: " $SCCACHE_DIR
|
||||
|
||||
echo "_____ Building target: "$CARGO_TARGET" _____"
|
||||
time cargo build --target $CARGO_TARGET --release --features final
|
||||
time cargo build --target $CARGO_TARGET --release -p evmbin
|
||||
time cargo build --target $CARGO_TARGET --release -p ethstore-cli
|
||||
time cargo build --target $CARGO_TARGET --release -p ethkey-cli
|
||||
time cargo build --target $CARGO_TARGET --release -p whisper-cli
|
||||
time cargo build --target $CARGO_TARGET --verbose --release --features final
|
||||
time cargo build --target $CARGO_TARGET --verbose --release -p evmbin
|
||||
time cargo build --target $CARGO_TARGET --verbose --release -p ethstore-cli
|
||||
time cargo build --target $CARGO_TARGET --verbose --release -p ethkey-cli
|
||||
time cargo build --target $CARGO_TARGET --verbose --release -p whisper-cli
|
||||
|
||||
echo "__________Sign binaries__________"
|
||||
scripts/gitlab/sign-win.cmd $keyfile $certpass target/$CARGO_TARGET/release/parity.exe
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
#!/bin/bash
|
||||
##ARGUMENTS: 1. Docker target
|
||||
set -e # fail on any error
|
||||
set -u # treat unset variables as error
|
||||
|
||||
if [ "$CI_COMMIT_REF_NAME" == "master" ];
|
||||
then export DOCKER_BUILD_TAG="${SCHEDULE_TAG:-latest}";
|
||||
else export DOCKER_BUILD_TAG=$CI_COMMIT_REF_NAME;
|
||||
fi
|
||||
docker login -u $Docker_Hub_User_Parity -p $Docker_Hub_Pass_Parity
|
||||
|
||||
echo "__________Docker TAG__________"
|
||||
echo $DOCKER_BUILD_TAG
|
||||
|
||||
echo "__________Docker target__________"
|
||||
export DOCKER_TARGET=$1
|
||||
echo $DOCKER_TARGET
|
||||
|
||||
echo "__________Docker build and push__________"
|
||||
docker build --build-arg TARGET=$DOCKER_TARGET --no-cache=true --tag parity/$DOCKER_TARGET:$DOCKER_BUILD_TAG -f scripts/docker/hub/Dockerfile .
|
||||
docker push parity/$DOCKER_TARGET:$DOCKER_BUILD_TAG
|
||||
docker logout
|
||||
@@ -33,8 +33,8 @@ update_wiki_docs() {
|
||||
|
||||
setup_git() {
|
||||
echo "__________Set github__________"
|
||||
git config --global user.email "devops@parity.com"
|
||||
git config --global user.name "Devops Parity"
|
||||
git config --global user.email "devops-team@parity.io"
|
||||
git config --global user.name "Devops Team Parity"
|
||||
}
|
||||
|
||||
set_remote_wiki() {
|
||||
@@ -51,8 +51,11 @@ commit_files() {
|
||||
|
||||
upload_files() {
|
||||
echo "__________Upload files__________"
|
||||
git push -q origin HEAD
|
||||
git push -q -f --tags
|
||||
# this version of git (2.7.4) will dump the token on failure
|
||||
git push -q origin HEAD 2>&1 \
|
||||
| sed -r "s|(${GITHUB_USER}):[a-f0-9]+@|\1:REDACTED@|g"
|
||||
git push -q -f --tags 2>&1 \
|
||||
| sed -r "s|(${GITHUB_USER}):[a-f0-9]+@|\1:REDACTED@|g"
|
||||
}
|
||||
|
||||
RPC_TRAITS_DIR="rpc/src/v1/traits"
|
||||
|
||||
@@ -7,10 +7,7 @@ echo "__________Register Release__________"
|
||||
DATA="secret=$RELEASES_SECRET"
|
||||
|
||||
echo "Pushing release to Mainnet"
|
||||
./scripts/gitlab/safe-curl.sh $DATA "http://update.parity.io:1337/push-release/${SCHEDULE_TAG:-${CI_COMMIT_REF_NAME}}/$CI_COMMIT_SHA"
|
||||
|
||||
echo "Pushing release to Kovan"
|
||||
./scripts/gitlab/safe-curl.sh $DATA "http://update.parity.io:1338/push-release/${SCHEDULE_TAG:-${CI_COMMIT_REF_NAME}}/$CI_COMMIT_SHA"
|
||||
./tools/safe-curl.sh $DATA "http://update.parity.io:1337/push-release/${SCHEDULE_TAG:-${CI_COMMIT_REF_NAME}}/$CI_COMMIT_SHA"
|
||||
|
||||
cd artifacts
|
||||
ls -l | sort -k9
|
||||
@@ -29,9 +26,7 @@ do
|
||||
case $DIR in
|
||||
x86_64* )
|
||||
DATA="commit=$CI_COMMIT_SHA&sha3=$sha3&filename=parity$WIN&secret=$RELEASES_SECRET"
|
||||
../../scripts/gitlab/safe-curl.sh $DATA "http://update.parity.io:1337/push-build/${SCHEDULE_TAG:-${CI_COMMIT_REF_NAME}}/$DIR"
|
||||
# Kovan
|
||||
../../scripts/gitlab/safe-curl.sh $DATA "http://update.parity.io:1338/push-build/${SCHEDULE_TAG:-${CI_COMMIT_REF_NAME}}/$DIR"
|
||||
../../tools/safe-curl.sh $DATA "http://update.parity.io:1337/push-build/${SCHEDULE_TAG:-${CI_COMMIT_REF_NAME}}/$DIR"
|
||||
;;
|
||||
esac
|
||||
cd ..
|
||||
|
||||
@@ -3,15 +3,11 @@
|
||||
set -e # fail on any error
|
||||
set -u # treat unset variables as error
|
||||
|
||||
# some necromancy:
|
||||
# gsub(/"/, "", $2) deletes "qoutes"
|
||||
# gsub(/ /, "", $2) deletes whitespaces
|
||||
TRACK=`awk -F '=' '/^track/ {gsub(/"/, "", $2); gsub(/ /, "", $2); print $2}' ./util/version/Cargo.toml`
|
||||
echo Track is: $TRACK
|
||||
# prepare variables
|
||||
VERSION=v"$(sed -r -n '1,/^version/s/^version = "([^"]+)".*$/\1/p' Cargo.toml)"
|
||||
TRACK=$(cat ./tools/TRACK)
|
||||
echo "Track is: ${TRACK}"
|
||||
VERSION=$(cat ./tools/VERSION)
|
||||
SNAP_PACKAGE="parity_"$VERSION"_"$BUILD_ARCH".snap"
|
||||
CARGO_TARGET="$(ls artifacts)"
|
||||
# Choose snap release channel based on parity ethereum version track
|
||||
case ${TRACK} in
|
||||
nightly) export GRADE="devel" CHANNEL="edge";;
|
||||
@@ -20,12 +16,8 @@ case ${TRACK} in
|
||||
*) echo "No release" && exit 0;;
|
||||
esac
|
||||
|
||||
# Release untagged versions from branches to the candidate snap channel
|
||||
case ${CI_COMMIT_REF_NAME} in
|
||||
beta|stable) export GRADE="stable" CHANNEL="candidate";;
|
||||
esac
|
||||
echo "__________Create snap package__________"
|
||||
echo "Release channel :" $GRADE " Branch/tag: " $CI_COMMIT_REF_NAME
|
||||
echo "Release channel :" $GRADE " Branch/tag: " $CI_COMMIT_REF_NAME "Track: " ${TRACK}
|
||||
echo $VERSION:$GRADE:$BUILD_ARCH:$CARGO_TARGET
|
||||
|
||||
sed -e 's/$VERSION/'"$VERSION"'/g' \
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
#!/bin/bash
|
||||
# ARGUMENT $1 Rust flavor to run test with (stable/beta/nightly)
|
||||
|
||||
echo "________Running test-linux.sh________"
|
||||
set -e # fail on any error
|
||||
set -u # treat unset variables as error
|
||||
|
||||
FEATURES="json-tests,ci-skip-tests"
|
||||
OPTIONS="--release"
|
||||
OPTIONS=""
|
||||
#use nproc `linux only
|
||||
THREADS=$(nproc)
|
||||
|
||||
rustup default $1
|
||||
rustup show
|
||||
|
||||
echo "________Running Parity Full Test Suite________"
|
||||
time cargo test $OPTIONS --features "$FEATURES" --locked --all --target $CARGO_TARGET -- --test-threads $THREADS
|
||||
# Why are we using RUSTFLAGS? See https://github.com/paritytech/parity-ethereum/pull/10719
|
||||
CARGO_INCREMENTAL=0 RUSTFLAGS="-C opt-level=3 -C overflow-checks=on -C debuginfo=2" time cargo test $OPTIONS --features "$FEATURES" --locked --all --target $CARGO_TARGET --verbose --color=never -- --test-threads $THREADS
|
||||
|
||||
@@ -6,7 +6,7 @@ echo "________Running validate_chainspecs.sh________"
|
||||
ERR=0
|
||||
|
||||
echo "________Validate chainspecs________"
|
||||
time cargo build --release -p chainspec
|
||||
time cargo build --release -p chainspec --verbose --color=always
|
||||
|
||||
for spec in ethcore/res/*.json; do
|
||||
if ! ./target/release/chainspec "$spec"; then ERR=1; fi
|
||||
|
||||
@@ -168,7 +168,6 @@ pub struct Discovery<'a> {
|
||||
discovery_id: NodeId,
|
||||
discovery_nodes: HashSet<NodeId>,
|
||||
node_buckets: Vec<NodeBucket>,
|
||||
|
||||
// Sometimes we don't want to add nodes to the NodeTable, but still want to
|
||||
// keep track of them to avoid excessive pinging (happens when an unknown node sends
|
||||
// a discovery request to us -- the node might be on a different net).
|
||||
@@ -257,7 +256,7 @@ impl<'a> Discovery<'a> {
|
||||
Ok(()) => None,
|
||||
Err(BucketError::Ourselves) => None,
|
||||
Err(BucketError::NotInTheBucket{node_entry, bucket_distance}) => Some((node_entry, bucket_distance))
|
||||
}.map(|(node_entry, bucket_distance)| {
|
||||
}.and_then(|(node_entry, bucket_distance)| {
|
||||
trace!(target: "discovery", "Adding a new node {:?} into our bucket {}", &node_entry, bucket_distance);
|
||||
|
||||
let mut added = HashMap::with_capacity(1);
|
||||
@@ -265,7 +264,7 @@ impl<'a> Discovery<'a> {
|
||||
|
||||
let node_to_ping = {
|
||||
let bucket = &mut self.node_buckets[bucket_distance];
|
||||
bucket.nodes.push_front(BucketEntry::new(node_entry));
|
||||
bucket.nodes.push_front(BucketEntry::new(node_entry.clone()));
|
||||
if bucket.nodes.len() > BUCKET_SIZE {
|
||||
select_bucket_ping(bucket.nodes.iter())
|
||||
} else {
|
||||
@@ -275,7 +274,12 @@ impl<'a> Discovery<'a> {
|
||||
if let Some(node) = node_to_ping {
|
||||
self.try_ping(node, PingReason::Default);
|
||||
};
|
||||
TableUpdates{added, removed: HashSet::new()}
|
||||
|
||||
if node_entry.endpoint.is_valid_sync_node() {
|
||||
Some(TableUpdates { added, removed: HashSet::new() })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -518,7 +522,18 @@ impl<'a> Discovery<'a> {
|
||||
|
||||
fn on_ping(&mut self, rlp: &Rlp, node_id: &NodeId, from: &SocketAddr, echo_hash: &[u8]) -> Result<Option<TableUpdates>, Error> {
|
||||
trace!(target: "discovery", "Got Ping from {:?}", &from);
|
||||
let ping_from = NodeEndpoint::from_rlp(&rlp.at(1)?)?;
|
||||
let ping_from = if let Ok(node_endpoint) = NodeEndpoint::from_rlp(&rlp.at(1)?) {
|
||||
node_endpoint
|
||||
} else {
|
||||
let mut address = from.clone();
|
||||
// address here is the node's tcp port. If we are unable to get the `NodeEndpoint` from the `ping_from`
|
||||
// rlp field then this is most likely a BootNode, set the tcp port to 0 because it can not be used for syncing.
|
||||
address.set_port(0);
|
||||
NodeEndpoint {
|
||||
address,
|
||||
udp_port: from.port()
|
||||
}
|
||||
};
|
||||
let ping_to = NodeEndpoint::from_rlp(&rlp.at(2)?)?;
|
||||
let timestamp: u64 = rlp.val_at(3)?;
|
||||
self.check_timestamp(timestamp)?;
|
||||
@@ -540,7 +555,7 @@ impl<'a> Discovery<'a> {
|
||||
self.send_packet(PACKET_PONG, from, &response.drain())?;
|
||||
|
||||
let entry = NodeEntry { id: *node_id, endpoint: pong_to.clone() };
|
||||
if !entry.endpoint.is_valid() {
|
||||
if !entry.endpoint.is_valid_discovery_node() {
|
||||
debug!(target: "discovery", "Got bad address: {:?}", entry);
|
||||
} else if !self.is_allowed(&entry) {
|
||||
debug!(target: "discovery", "Address not allowed: {:?}", entry);
|
||||
@@ -728,7 +743,7 @@ impl<'a> Discovery<'a> {
|
||||
trace!(target: "discovery", "Got {} Neighbours from {:?}", results_count, &from);
|
||||
for r in rlp.at(0)?.iter() {
|
||||
let endpoint = NodeEndpoint::from_rlp(&r)?;
|
||||
if !endpoint.is_valid() {
|
||||
if !endpoint.is_valid_discovery_node() {
|
||||
debug!(target: "discovery", "Bad address: {:?}", endpoint);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -103,10 +103,16 @@ impl NodeEndpoint {
|
||||
self.to_rlp(rlp);
|
||||
}
|
||||
|
||||
/// Validates that the port is not 0 and address IP is specified
|
||||
pub fn is_valid(&self) -> bool {
|
||||
self.udp_port != 0 && self.address.port() != 0 &&
|
||||
match self.address {
|
||||
/// Validates that the tcp port is not 0 and that the node is a valid discovery node (i.e. `is_valid_discovery_node()` is true).
|
||||
/// Sync happens over tcp.
|
||||
pub fn is_valid_sync_node(&self) -> bool {
|
||||
self.is_valid_discovery_node() && self.address.port() != 0
|
||||
}
|
||||
|
||||
/// Validates that the udp port is not 0 and address IP is specified.
|
||||
/// Peer discovery happens over udp.
|
||||
pub fn is_valid_discovery_node(&self) -> bool {
|
||||
self.udp_port != 0 && match self.address {
|
||||
SocketAddr::V4(a) => !a.ip().is_unspecified(),
|
||||
SocketAddr::V6(a) => !a.ip().is_unspecified()
|
||||
}
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
[package]
|
||||
name = "parity-version"
|
||||
# NOTE: this value is used for Parity Ethereum version string (via env CARGO_PKG_VERSION)
|
||||
version = "2.5.0"
|
||||
version = "2.5.3"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
build = "build.rs"
|
||||
|
||||
[package.metadata]
|
||||
# This versions track. Should be changed to `stable` or `beta` when on respective branches.
|
||||
# Used by auto-updater and for Parity version string.
|
||||
track = "nightly"
|
||||
track = "beta"
|
||||
|
||||
# Network specific settings, used ONLY by auto-updater.
|
||||
# Latest supported fork blocks.
|
||||
|
||||
@@ -264,17 +264,17 @@ impl Message {
|
||||
|
||||
let mut rng = {
|
||||
let mut thread_rng = ::rand::thread_rng();
|
||||
|
||||
XorShiftRng::from_seed(thread_rng.gen::<[u32; 4]>())
|
||||
};
|
||||
|
||||
assert!(params.ttl > 0);
|
||||
|
||||
let expiry = {
|
||||
let after_mining = SystemTime::now().checked_sub(Duration::from_millis(params.work))
|
||||
.ok_or(Error::TimestampOverflow)?;
|
||||
let since_epoch = after_mining.duration_since(time::UNIX_EPOCH)
|
||||
.expect("time after now is after unix epoch; qed");
|
||||
let since_epoch = SystemTime::now()
|
||||
.checked_add(Duration::from_secs(params.ttl))
|
||||
.and_then(|t| t.checked_add(Duration::from_millis(params.work)))
|
||||
.ok_or(Error::TimestampOverflow)?
|
||||
.duration_since(time::UNIX_EPOCH).expect("time after now is after unix epoch; qed");
|
||||
|
||||
// round up the sub-second to next whole second.
|
||||
since_epoch.as_secs() + if since_epoch.subsec_nanos() == 0 { 0 } else { 1 }
|
||||
|
||||
Reference in New Issue
Block a user