Compare commits
71 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
adabd8198c | ||
|
|
c2487cfe07 | ||
|
|
e0141f8324 | ||
|
|
b52ac20660 | ||
|
|
3c85f29f11 | ||
|
|
d9673b0d6b | ||
|
|
89f828be1c | ||
|
|
ec56b1f09d | ||
|
|
95236d25b2 | ||
|
|
7b2afdfc8c | ||
|
|
440e52f410 | ||
|
|
8840a293dd | ||
|
|
89d627769e | ||
|
|
4e2e88a620 | ||
|
|
ebf51c0be0 | ||
|
|
04c6867660 | ||
|
|
0199acbece | ||
|
|
e4c2fe9e72 | ||
|
|
407de5e8c4 | ||
|
|
7d26a82232 | ||
|
|
3b23817936 | ||
|
|
aa8487c1d0 | ||
|
|
9cb8606103 | ||
|
|
6cf3ba7efd | ||
|
|
023e511f83 | ||
|
|
17042e9c32 | ||
|
|
f2c34f7ca2 | ||
|
|
375a8daeb4 | ||
|
|
b700ff3501 | ||
|
|
9519493e32 | ||
|
|
037fd1b309 | ||
|
|
78a534633d | ||
|
|
effead9ba5 | ||
|
|
a8ee3c97e6 | ||
|
|
fb461659c7 | ||
|
|
a574df3132 | ||
|
|
d83143d0ba | ||
|
|
f875175325 | ||
|
|
c9db8ea21d | ||
|
|
a16bad4175 | ||
|
|
595dac6c3f | ||
|
|
82a148a99b | ||
|
|
4320c9bc4f | ||
|
|
23d977ecce | ||
|
|
ab27848dc4 | ||
|
|
742a6007fe | ||
|
|
91933d857d | ||
|
|
3e1d73126c | ||
|
|
7014642815 | ||
|
|
1bd4564216 | ||
|
|
97cb010df8 | ||
|
|
ed18c7b54c | ||
|
|
e71598d876 | ||
|
|
3d0ce10fa6 | ||
|
|
cfc8df156b | ||
|
|
94cb3b6e0e | ||
|
|
fefec000fb | ||
|
|
c7ded6a785 | ||
|
|
2fbb952cdd | ||
|
|
e2ab3e4f5b | ||
|
|
1871275ecd | ||
|
|
afc1b72611 | ||
|
|
c5c3fb6a75 | ||
|
|
bceb883d99 | ||
|
|
fcccbf3b75 | ||
|
|
9ad71b7baa | ||
|
|
4311d43497 | ||
|
|
0815cc3b83 | ||
|
|
b21844b371 | ||
|
|
f825048efa | ||
|
|
2cbffe36e2 |
298
.gitlab-ci.yml
298
.gitlab-ci.yml
@@ -2,18 +2,20 @@ stages:
|
||||
- test
|
||||
- build
|
||||
- publish
|
||||
- publish-onchain
|
||||
- optional
|
||||
|
||||
image: parity/rust:gitlab-ci
|
||||
|
||||
image: parity/rust-parity-ethereum-build:xenial
|
||||
variables:
|
||||
GIT_STRATEGY: fetch
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
CI_SERVER_NAME: "GitLab CI"
|
||||
CARGO_HOME: "${CI_PROJECT_DIR}/.cargo"
|
||||
CARGO_TARGET: x86_64-unknown-linux-gnu
|
||||
|
||||
.no_git: &no_git # disable git strategy
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
GIT_SUBMODULE_STRATEGY: none
|
||||
|
||||
.releaseable_branches: # list of git refs for building GitLab artifacts (think "pre-release binaries")
|
||||
only: &releaseable_branches
|
||||
- stable
|
||||
@@ -21,80 +23,177 @@ variables:
|
||||
- tags
|
||||
- schedules
|
||||
|
||||
|
||||
.collect_artifacts: &collect_artifacts
|
||||
artifacts:
|
||||
name: "${CI_JOB_NAME}_${SCHEDULE_TAG:-${CI_COMMIT_REF_NAME}}"
|
||||
when: on_success
|
||||
expire_in: 1 mos
|
||||
paths:
|
||||
- artifacts/
|
||||
- artifacts/
|
||||
|
||||
.determine_version: &determine_version
|
||||
- VERSION="$(sed -r -n '1,/^version/s/^version = "([^"]+)".*$/\1/p' Cargo.toml)"
|
||||
- DATE_STR="$(date +%Y%m%d)"
|
||||
- ID_SHORT="$(echo ${CI_COMMIT_SHA} | cut -c 1-7)"
|
||||
- test "${SCHEDULE_TAG:-${CI_COMMIT_REF_NAME}}" = "nightly" && VERSION="${VERSION}-${ID_SHORT}-${DATE_STR}"
|
||||
- export VERSION
|
||||
- echo "Version = ${VERSION}"
|
||||
.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_debug.log
|
||||
RUST_LOG=sccache=debug
|
||||
sccache --start-server
|
||||
- sccache -s
|
||||
after_script:
|
||||
# sccache debug info
|
||||
- if test -e sccache_debug.log;
|
||||
then
|
||||
echo "_____sccache_debug.log listing start:_____";
|
||||
cat sccache_debug.log;
|
||||
echo "_____sccache_debug.log listing end_____";
|
||||
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
|
||||
|
||||
|
||||
cargo-check 0 3:
|
||||
stage: test
|
||||
<<: *docker-cache-status
|
||||
script:
|
||||
- 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 --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" --verbose --color=always
|
||||
- sccache -s
|
||||
|
||||
cargo-audit:
|
||||
stage: test
|
||||
<<: *docker-cache-status
|
||||
script:
|
||||
- cargo audit
|
||||
|
||||
validate-chainspecs:
|
||||
stage: test
|
||||
<<: *docker-cache-status
|
||||
script:
|
||||
- ./scripts/gitlab/validate-chainspecs.sh
|
||||
- sccache -s
|
||||
|
||||
test-cpp:
|
||||
stage: build
|
||||
<<: *docker-cache-status
|
||||
script:
|
||||
- ./scripts/gitlab/test-cpp.sh
|
||||
- sccache -s
|
||||
|
||||
test-linux:
|
||||
stage: test
|
||||
variables:
|
||||
RUN_TESTS: all
|
||||
stage: build
|
||||
<<: *docker-cache-status
|
||||
script:
|
||||
- scripts/gitlab/test-all.sh
|
||||
- ./scripts/gitlab/test-linux.sh stable
|
||||
- sccache -s
|
||||
tags:
|
||||
- linux-docker
|
||||
|
||||
test-audit:
|
||||
stage: test
|
||||
script:
|
||||
- set -e
|
||||
- set -u
|
||||
- cargo audit
|
||||
tags:
|
||||
- linux-docker
|
||||
|
||||
build-linux:
|
||||
test-linux-beta:
|
||||
stage: build
|
||||
only: *releaseable_branches
|
||||
<<: *docker-cache-status
|
||||
script:
|
||||
- scripts/gitlab/build-unix.sh
|
||||
- ./scripts/gitlab/test-linux.sh beta
|
||||
- sccache -s
|
||||
<<: *collect_artifacts
|
||||
tags:
|
||||
- linux-docker
|
||||
|
||||
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-on-linux
|
||||
only: *releaseable_branches
|
||||
image: parity/rust-parity-ethereum-build:i386
|
||||
variables:
|
||||
CARGO_TARGET: i686-unknown-linux-gnu
|
||||
|
||||
build-linux-arm64:
|
||||
<<: *build-on-linux
|
||||
only: *releaseable_branches
|
||||
image: parity/rust-parity-ethereum-build:arm64
|
||||
variables:
|
||||
CARGO_TARGET: aarch64-unknown-linux-gnu
|
||||
|
||||
build-linux-armhf:
|
||||
<<: *build-on-linux
|
||||
only: *releaseable_branches
|
||||
image: parity/rust-parity-ethereum-build:armhf
|
||||
variables:
|
||||
CARGO_TARGET: armv7-unknown-linux-gnueabihf
|
||||
|
||||
build-darwin:
|
||||
stage: build
|
||||
<<: *collect_artifacts
|
||||
only: *releaseable_branches
|
||||
variables:
|
||||
CARGO_TARGET: x86_64-apple-darwin
|
||||
CARGO_HOME: "${CI_PROJECT_DIR}/.cargo"
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
script:
|
||||
- scripts/gitlab/build-unix.sh
|
||||
- scripts/gitlab/build-linux.sh
|
||||
tags:
|
||||
- rust-osx
|
||||
<<: *collect_artifacts
|
||||
|
||||
build-windows:
|
||||
stage: build
|
||||
<<: *collect_artifacts
|
||||
only: *releaseable_branches
|
||||
variables:
|
||||
CARGO_TARGET: x86_64-pc-windows-msvc
|
||||
CARGO_HOME: "C:/ci-cache/parity-ethereum/cargo/$CI_JOB_NAME"
|
||||
GIT_SUBMODULE_STRATEGY: none
|
||||
script:
|
||||
- sh scripts/gitlab/build-windows.sh
|
||||
tags:
|
||||
- rust-windows
|
||||
<<: *collect_artifacts
|
||||
- rust-windows
|
||||
|
||||
publish-docker:
|
||||
stage: publish
|
||||
only: *releaseable_branches
|
||||
cache: {}
|
||||
cache: {}
|
||||
dependencies:
|
||||
- build-linux
|
||||
tags:
|
||||
@@ -102,57 +201,43 @@ publish-docker:
|
||||
script:
|
||||
- scripts/gitlab/publish-docker.sh parity
|
||||
|
||||
publish-snap:
|
||||
stage: optional #publish
|
||||
publish-snap: &publish-snap
|
||||
stage: publish
|
||||
only: *releaseable_branches
|
||||
<<: *collect_artifacts
|
||||
image: snapcore/snapcraft
|
||||
variables:
|
||||
BUILD_ARCH: amd64
|
||||
cache: {}
|
||||
before_script: *determine_version
|
||||
dependencies:
|
||||
- build-linux
|
||||
tags:
|
||||
- rust-stable
|
||||
script:
|
||||
- scripts/gitlab/publish-snap.sh
|
||||
allow_failure: true
|
||||
<<: *collect_artifacts
|
||||
|
||||
publish-onnet-update:
|
||||
stage: publish-onchain
|
||||
only: *releaseable_branches
|
||||
BUILD_ARCH: amd64
|
||||
cache: {}
|
||||
dependencies:
|
||||
- build-linux
|
||||
- build-darwin
|
||||
- build-windows
|
||||
- publish-awss3-release
|
||||
before_script: *determine_version
|
||||
script:
|
||||
- scripts/gitlab/publish-onnet-update.sh
|
||||
tags:
|
||||
- linux-docker
|
||||
script:
|
||||
- scripts/gitlab/publish-snap.sh
|
||||
|
||||
# configures aws for fast uploads/syncs
|
||||
.s3-before-script: &s3-before-script
|
||||
before_script:
|
||||
- mkdir -p ${HOME}/.aws
|
||||
- |
|
||||
cat > ${HOME}/.aws/config <<EOC
|
||||
[default]
|
||||
s3 =
|
||||
max_concurrent_requests = 20
|
||||
max_queue_size = 10000
|
||||
multipart_threshold = 64MB
|
||||
multipart_chunksize = 16MB
|
||||
max_bandwidth = 50MB/s
|
||||
use_accelerate_endpoint = false
|
||||
addressing_style = path
|
||||
EOC
|
||||
publish-snap-i386:
|
||||
<<: *publish-snap
|
||||
variables:
|
||||
BUILD_ARCH: i386
|
||||
dependencies:
|
||||
- build-linux-i386
|
||||
|
||||
publish-awss3-release:
|
||||
image: parity/awscli:latest
|
||||
publish-snap-arm64:
|
||||
<<: *publish-snap
|
||||
variables:
|
||||
BUILD_ARCH: arm64
|
||||
dependencies:
|
||||
- build-linux-arm64
|
||||
|
||||
publish-snap-armhf:
|
||||
<<: *publish-snap
|
||||
variables:
|
||||
BUILD_ARCH: armhf
|
||||
dependencies:
|
||||
- build-linux-armhf
|
||||
|
||||
publish-onchain:
|
||||
stage: publish
|
||||
only: *releaseable_branches
|
||||
cache: {}
|
||||
@@ -160,47 +245,48 @@ publish-awss3-release:
|
||||
- build-linux
|
||||
- build-darwin
|
||||
- build-windows
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
<<: *s3-before-script
|
||||
script:
|
||||
- scripts/gitlab/publish-onchain.sh
|
||||
tags:
|
||||
- linux-docker
|
||||
|
||||
publish-awss3-release:
|
||||
image: parity/awscli:latest
|
||||
stage: publish
|
||||
only: *releaseable_branches
|
||||
<<: *no_git
|
||||
cache: {}
|
||||
dependencies:
|
||||
- build-linux
|
||||
- build-darwin
|
||||
- build-windows
|
||||
script:
|
||||
- echo "__________Push binaries to AWS S3____________"
|
||||
- case "${SCHEDULE_TAG:-${CI_COMMIT_REF_NAME}}" in
|
||||
(beta|stable|nightly)
|
||||
export BUCKET=releases.parity.io/ethereum;
|
||||
;;
|
||||
(*)
|
||||
export BUCKET=builds-parity;
|
||||
;;
|
||||
esac
|
||||
(beta|stable|nightly)
|
||||
export BUCKET=releases.parity.io/ethereum;
|
||||
;;
|
||||
(*)
|
||||
export BUCKET=builds-parity;
|
||||
;;
|
||||
esac
|
||||
- aws s3 sync ./artifacts s3://${BUCKET}/${SCHEDULE_TAG:-${CI_COMMIT_REF_NAME}}/
|
||||
after_script:
|
||||
- aws s3 ls s3://${BUCKET}/${SCHEDULE_TAG:-${CI_COMMIT_REF_NAME}}/
|
||||
--recursive --human-readable --summarize
|
||||
- echo "__________Read from S3____________"
|
||||
- aws s3 ls s3://${BUCKET}/${SCHEDULE_TAG:-${CI_COMMIT_REF_NAME}} --recursive --human-readable --summarize
|
||||
tags:
|
||||
- linux-docker
|
||||
- linux-docker
|
||||
|
||||
publish-docs:
|
||||
stage: publish
|
||||
image: parity/rust-parity-ethereum-docs:xenial
|
||||
only:
|
||||
- tags
|
||||
except:
|
||||
- nightly
|
||||
cache: {}
|
||||
cache: {}
|
||||
dependencies: []
|
||||
script:
|
||||
- scripts/gitlab/publish-docs.sh
|
||||
tags:
|
||||
- linux-docker
|
||||
|
||||
build-android:
|
||||
stage: optional
|
||||
image: parity/rust-android:gitlab-ci
|
||||
variables:
|
||||
CARGO_TARGET: armv7-linux-androideabi
|
||||
script:
|
||||
- scripts/gitlab/build-unix.sh
|
||||
tags:
|
||||
- linux-docker
|
||||
allow_failure: true
|
||||
<<: *collect_artifacts
|
||||
|
||||
|
||||
294
CHANGELOG.md
294
CHANGELOG.md
@@ -1,162 +1,152 @@
|
||||
## Parity-Ethereum [v2.3.0](https://github.com/paritytech/parity-ethereum/releases/tag/v2.3.0) (2019-01-16)
|
||||
## Parity-Ethereum [v2.4.3](https://github.com/paritytech/parity-ethereum/releases/tag/v2.4.3) (2019-03-22)
|
||||
|
||||
Parity-Ethereum 2.3.0-beta is a consensus-relevant security release that reverts Constantinople on the Ethereum network. Upgrading is mandatory for Ethereum, and strongly recommended for other networks.
|
||||
|
||||
- **Consensus** - Ethereum Network: Pull Constantinople protocol upgrade on Ethereum (#10189)
|
||||
- Read more: [Security Alert: Ethereum Constantinople Postponement](https://blog.ethereum.org/2019/01/15/security-alert-ethereum-constantinople-postponement/)
|
||||
- **Networking** - All networks: Ping nodes from discovery (#10167)
|
||||
- **Wasm** - Kovan Network: Update pwasm-utils to 0.6.1 (#10134)
|
||||
|
||||
Other notable changes:
|
||||
|
||||
- Existing blocks in the database are now kept when restoring a Snapshot. (#8643)
|
||||
- Block and transaction propagation is improved significantly. (#9954)
|
||||
- The ERC-191 Signed Data Standard is now supported by `personal_sign191`. (#9701)
|
||||
- Add support for ERC-191/712 `eth_signTypedData` as a standard for machine-verifiable and human-readable typed data signing with Ethereum keys. (#9631)
|
||||
- Add support for ERC-1186 `eth_getProof` (#9001)
|
||||
- Add experimental RPCs flag to enable ERC-191, ERC-712, and ERC-1186 APIs via `--jsonrpc-experimental` (#9928)
|
||||
- Make `CALLCODE` to trace value to be the code address. (#9881)
|
||||
|
||||
Configuration changes:
|
||||
|
||||
- The EIP-98 transition is now disabled by default. If you previously had no `eip98transition` specified in your chain specification, you would enable this now manually on block `0x0`. (#9955)
|
||||
- Also, unknown fields in chain specs are now rejected. (#9972)
|
||||
- The Tendermint engine was removed from Parity Ethereum and is no longer available and maintained. (#9980)
|
||||
- Ropsten testnet data and keys moved from `test/` to `ropsten/` subdir. To reuse your old keys and data either copy or symlink them to the new location. (#10123)
|
||||
- Strict empty steps validation (#10041)
|
||||
- If you have a chain with`empty_steps` already running, some blocks most likely contain non-strict entries (unordered or duplicated empty steps). In this release `strict_empty_steps_transition` is enabled by default at block `0x0` for any chain with `empty_steps`.
|
||||
- If your network uses `empty_steps` you **must** (A) plan a hard fork and change `strict_empty_steps_transition` to the desired fork block and (B) update the clients of the whole network to 2.2.7-stable / 2.3.0-beta. If for some reason you don't want to do this please set`strict_empty_steps_transition` to `0xfffffffff` to disable it.
|
||||
|
||||
_Note:_ This release marks Parity 2.3 as _beta_. All versions of Parity 2.2 are now considered _stable_.
|
||||
Parity-Ethereum 2.4.3-beta is a bugfix release that improves performance and stability. This patch release contains a critical bug fix where serving light clients previously led to client crashes. Upgrading is highly recommended.
|
||||
|
||||
The full list of included changes:
|
||||
- 2.4.3 beta backports ([#10508](https://github.com/paritytech/parity-ethereum/pull/10508))
|
||||
- Version: bump beta
|
||||
- Add additional request tests ([#10503](https://github.com/paritytech/parity-ethereum/pull/10503))
|
||||
|
||||
- Backports for 2.3.0 beta ([#10164](https://github.com/paritytech/parity-ethereum/pull/10164))
|
||||
- Snap: fix path in script ([#10157](https://github.com/paritytech/parity-ethereum/pull/10157))
|
||||
- Make sure parent block is not in importing queue when importing ancient blocks ([#10138](https://github.com/paritytech/parity-ethereum/pull/10138))
|
||||
- Ci: re-enable snap publishing ([#10142](https://github.com/paritytech/parity-ethereum/pull/10142))
|
||||
- Hf in POA Core (2019-01-18) - Constantinople ([#10155](https://github.com/paritytech/parity-ethereum/pull/10155))
|
||||
- Update EWF's tobalaba chainspec ([#10152](https://github.com/paritytech/parity-ethereum/pull/10152))
|
||||
- Replace ethcore-logger with env-logger. ([#10102](https://github.com/paritytech/parity-ethereum/pull/10102))
|
||||
- Finality: dont require chain head to be in the chain ([#10054](https://github.com/paritytech/parity-ethereum/pull/10054))
|
||||
- Remove caching for node connections ([#10143](https://github.com/paritytech/parity-ethereum/pull/10143))
|
||||
- Blooms file iterator empty on out of range position. ([#10145](https://github.com/paritytech/parity-ethereum/pull/10145))
|
||||
- Autogen docs for the "Configuring Parity Ethereum" wiki page. ([#10067](https://github.com/paritytech/parity-ethereum/pull/10067))
|
||||
- Misc: bump license header to 2019 ([#10135](https://github.com/paritytech/parity-ethereum/pull/10135))
|
||||
- Hide most of the logs from cpp example. ([#10139](https://github.com/paritytech/parity-ethereum/pull/10139))
|
||||
- Don't try to send oversized packets ([#10042](https://github.com/paritytech/parity-ethereum/pull/10042))
|
||||
- Private tx enabled flag added into STATUS packet ([#9999](https://github.com/paritytech/parity-ethereum/pull/9999))
|
||||
- Update pwasm-utils to 0.6.1 ([#10134](https://github.com/paritytech/parity-ethereum/pull/10134))
|
||||
- Extract blockchain from ethcore ([#10114](https://github.com/paritytech/parity-ethereum/pull/10114))
|
||||
- Ethcore: update hardcoded headers ([#10123](https://github.com/paritytech/parity-ethereum/pull/10123))
|
||||
- Identity fix ([#10128](https://github.com/paritytech/parity-ethereum/pull/10128))
|
||||
- Use LenCachingMutex to optimize verification. ([#10117](https://github.com/paritytech/parity-ethereum/pull/10117))
|
||||
- Pyethereum keystore support ([#9710](https://github.com/paritytech/parity-ethereum/pull/9710))
|
||||
- Bump rocksdb-sys to 0.5.5 ([#10124](https://github.com/paritytech/parity-ethereum/pull/10124))
|
||||
- Parity-clib: `async C bindings to RPC requests` + `subscribe/unsubscribe to websocket events` ([#9920](https://github.com/paritytech/parity-ethereum/pull/9920))
|
||||
- Refactor (hardware wallet) : reduce the number of threads ([#9644](https://github.com/paritytech/parity-ethereum/pull/9644))
|
||||
- Hf in POA Sokol (2019-01-04) ([#10077](https://github.com/paritytech/parity-ethereum/pull/10077))
|
||||
- Fix broken links ([#10119](https://github.com/paritytech/parity-ethereum/pull/10119))
|
||||
- Follow-up to [#10105](https://github.com/paritytech/parity-ethereum/issues/10105) ([#10107](https://github.com/paritytech/parity-ethereum/pull/10107))
|
||||
- Move EIP-712 crate back to parity-ethereum ([#10106](https://github.com/paritytech/parity-ethereum/pull/10106))
|
||||
- Move a bunch of stuff around ([#10101](https://github.com/paritytech/parity-ethereum/pull/10101))
|
||||
- Revert "Add --frozen when running cargo ([#10081](https://github.com/paritytech/parity-ethereum/pull/10081))" ([#10105](https://github.com/paritytech/parity-ethereum/pull/10105))
|
||||
- Fix left over small grumbles on whitespaces ([#10084](https://github.com/paritytech/parity-ethereum/pull/10084))
|
||||
- Add --frozen when running cargo ([#10081](https://github.com/paritytech/parity-ethereum/pull/10081))
|
||||
- Fix pubsub new_blocks notifications to include all blocks ([#9987](https://github.com/paritytech/parity-ethereum/pull/9987))
|
||||
- Update some dependencies for compilation with pc-windows-gnu ([#10082](https://github.com/paritytech/parity-ethereum/pull/10082))
|
||||
- Fill transaction hash on ethGetLog of light client. ([#9938](https://github.com/paritytech/parity-ethereum/pull/9938))
|
||||
- Update changelog update for 2.2.5-beta and 2.1.10-stable ([#10064](https://github.com/paritytech/parity-ethereum/pull/10064))
|
||||
- Implement len caching for parking_lot RwLock ([#10032](https://github.com/paritytech/parity-ethereum/pull/10032))
|
||||
- Update parking_lot to 0.7 ([#10050](https://github.com/paritytech/parity-ethereum/pull/10050))
|
||||
- Bump crossbeam. ([#10048](https://github.com/paritytech/parity-ethereum/pull/10048))
|
||||
- Ethcore: enable constantinople on ethereum ([#10031](https://github.com/paritytech/parity-ethereum/pull/10031))
|
||||
- Strict empty steps validation ([#10041](https://github.com/paritytech/parity-ethereum/pull/10041))
|
||||
- Center the Subtitle, use some CAPS ([#10034](https://github.com/paritytech/parity-ethereum/pull/10034))
|
||||
- Change test miner max memory to malloc reports. ([#10024](https://github.com/paritytech/parity-ethereum/pull/10024))
|
||||
- Sort the storage for private state ([#10018](https://github.com/paritytech/parity-ethereum/pull/10018))
|
||||
- Fix: test corpus_inaccessible panic ([#10019](https://github.com/paritytech/parity-ethereum/pull/10019))
|
||||
- Ci: move future releases to ethereum subdir on s3 ([#10017](https://github.com/paritytech/parity-ethereum/pull/10017))
|
||||
- Light(on_demand): decrease default time window to 10 secs ([#10016](https://github.com/paritytech/parity-ethereum/pull/10016))
|
||||
- Light client : failsafe crate (circuit breaker) ([#9790](https://github.com/paritytech/parity-ethereum/pull/9790))
|
||||
- Lencachingmutex ([#9988](https://github.com/paritytech/parity-ethereum/pull/9988))
|
||||
- Version and notification for private contract wrapper added ([#9761](https://github.com/paritytech/parity-ethereum/pull/9761))
|
||||
- Handle failing case for update account cache in require ([#9989](https://github.com/paritytech/parity-ethereum/pull/9989))
|
||||
- Add tokio runtime to ethcore io worker ([#9979](https://github.com/paritytech/parity-ethereum/pull/9979))
|
||||
- Move daemonize before creating account provider ([#10003](https://github.com/paritytech/parity-ethereum/pull/10003))
|
||||
- Docs: update changelogs ([#9990](https://github.com/paritytech/parity-ethereum/pull/9990))
|
||||
- Fix daemonize ([#10000](https://github.com/paritytech/parity-ethereum/pull/10000))
|
||||
- Fix Bloom migration ([#9992](https://github.com/paritytech/parity-ethereum/pull/9992))
|
||||
- Remove tendermint engine support ([#9980](https://github.com/paritytech/parity-ethereum/pull/9980))
|
||||
- Calculate gas for deployment transaction ([#9840](https://github.com/paritytech/parity-ethereum/pull/9840))
|
||||
- Fix unstable peers and slowness in sync ([#9967](https://github.com/paritytech/parity-ethereum/pull/9967))
|
||||
- Adds parity_verifySignature RPC method ([#9507](https://github.com/paritytech/parity-ethereum/pull/9507))
|
||||
- Improve block and transaction propagation ([#9954](https://github.com/paritytech/parity-ethereum/pull/9954))
|
||||
- Deny unknown fields for chainspec ([#9972](https://github.com/paritytech/parity-ethereum/pull/9972))
|
||||
- Fix docker build ([#9971](https://github.com/paritytech/parity-ethereum/pull/9971))
|
||||
- Ci: rearrange pipeline by logic ([#9970](https://github.com/paritytech/parity-ethereum/pull/9970))
|
||||
- Add changelogs for 2.0.9, 2.1.4, 2.1.6, and 2.2.1 ([#9963](https://github.com/paritytech/parity-ethereum/pull/9963))
|
||||
- Add Error message when sync is still in progress. ([#9475](https://github.com/paritytech/parity-ethereum/pull/9475))
|
||||
- Make CALLCODE to trace value to be the code address ([#9881](https://github.com/paritytech/parity-ethereum/pull/9881))
|
||||
- Fix light client informant while syncing ([#9932](https://github.com/paritytech/parity-ethereum/pull/9932))
|
||||
- Add a optional json dump state to evm-bin ([#9706](https://github.com/paritytech/parity-ethereum/pull/9706))
|
||||
- Disable EIP-98 transition by default ([#9955](https://github.com/paritytech/parity-ethereum/pull/9955))
|
||||
- Remove secret_store runtimes. ([#9888](https://github.com/paritytech/parity-ethereum/pull/9888))
|
||||
- Fix a deadlock ([#9952](https://github.com/paritytech/parity-ethereum/pull/9952))
|
||||
- Chore(eip712): remove unused `failure-derive` ([#9958](https://github.com/paritytech/parity-ethereum/pull/9958))
|
||||
- Do not use the home directory as the working dir in docker ([#9834](https://github.com/paritytech/parity-ethereum/pull/9834))
|
||||
- Prevent silent errors in daemon mode, closes [#9367](https://github.com/paritytech/parity-ethereum/issues/9367) ([#9946](https://github.com/paritytech/parity-ethereum/pull/9946))
|
||||
- Fix empty steps ([#9939](https://github.com/paritytech/parity-ethereum/pull/9939))
|
||||
- Adjust requests costs for light client ([#9925](https://github.com/paritytech/parity-ethereum/pull/9925))
|
||||
- Eip-1186: add `eth_getProof` RPC-Method ([#9001](https://github.com/paritytech/parity-ethereum/pull/9001))
|
||||
- Missing blocks in filter_changes RPC ([#9947](https://github.com/paritytech/parity-ethereum/pull/9947))
|
||||
- Allow rust-nightly builds fail in nightly builds ([#9944](https://github.com/paritytech/parity-ethereum/pull/9944))
|
||||
- Update eth-secp256k1 to include fix for BSDs ([#9935](https://github.com/paritytech/parity-ethereum/pull/9935))
|
||||
- Unbreak build on rust -stable ([#9934](https://github.com/paritytech/parity-ethereum/pull/9934))
|
||||
- Keep existing blocks when restoring a Snapshot ([#8643](https://github.com/paritytech/parity-ethereum/pull/8643))
|
||||
- Add experimental RPCs flag ([#9928](https://github.com/paritytech/parity-ethereum/pull/9928))
|
||||
- Clarify poll lifetime ([#9922](https://github.com/paritytech/parity-ethereum/pull/9922))
|
||||
- Docs(require rust 1.30) ([#9923](https://github.com/paritytech/parity-ethereum/pull/9923))
|
||||
- Use block header for building finality ([#9914](https://github.com/paritytech/parity-ethereum/pull/9914))
|
||||
- Simplify cargo audit ([#9918](https://github.com/paritytech/parity-ethereum/pull/9918))
|
||||
- Light-fetch: Differentiate between out-of-gas/manual throw and use required gas from response on failure ([#9824](https://github.com/paritytech/parity-ethereum/pull/9824))
|
||||
- Eip 191 ([#9701](https://github.com/paritytech/parity-ethereum/pull/9701))
|
||||
- Fix(logger): `reqwest` no longer a dependency ([#9908](https://github.com/paritytech/parity-ethereum/pull/9908))
|
||||
- Remove rust-toolchain file ([#9906](https://github.com/paritytech/parity-ethereum/pull/9906))
|
||||
- Foundation: 6692865, ropsten: 4417537, kovan: 9363457 ([#9907](https://github.com/paritytech/parity-ethereum/pull/9907))
|
||||
- Ethcore: use Machine::verify_transaction on parent block ([#9900](https://github.com/paritytech/parity-ethereum/pull/9900))
|
||||
- Chore(rpc-tests): remove unused rand ([#9896](https://github.com/paritytech/parity-ethereum/pull/9896))
|
||||
- Fix: Intermittent failing CI due to addr in use ([#9885](https://github.com/paritytech/parity-ethereum/pull/9885))
|
||||
- Chore(bump docopt): 0.8 -> 1.0 ([#9889](https://github.com/paritytech/parity-ethereum/pull/9889))
|
||||
- Use expect ([#9883](https://github.com/paritytech/parity-ethereum/pull/9883))
|
||||
- Use Weak reference in PubSubClient ([#9886](https://github.com/paritytech/parity-ethereum/pull/9886))
|
||||
- Ci: nuke the gitlab caches ([#9855](https://github.com/paritytech/parity-ethereum/pull/9855))
|
||||
- Remove unused code ([#9884](https://github.com/paritytech/parity-ethereum/pull/9884))
|
||||
- Fix json tracer overflow ([#9873](https://github.com/paritytech/parity-ethereum/pull/9873))
|
||||
- Allow to seal work on latest block ([#9876](https://github.com/paritytech/parity-ethereum/pull/9876))
|
||||
- Fix docker script ([#9854](https://github.com/paritytech/parity-ethereum/pull/9854))
|
||||
- Health endpoint ([#9847](https://github.com/paritytech/parity-ethereum/pull/9847))
|
||||
- Gitlab-ci: make android release build succeed ([#9743](https://github.com/paritytech/parity-ethereum/pull/9743))
|
||||
- Clean up existing benchmarks ([#9839](https://github.com/paritytech/parity-ethereum/pull/9839))
|
||||
- Update Callisto block reward code to support HF1 ([#9811](https://github.com/paritytech/parity-ethereum/pull/9811))
|
||||
- Option to disable keep alive for JSON-RPC http transport ([#9848](https://github.com/paritytech/parity-ethereum/pull/9848))
|
||||
- Classic.json Bootnode Update ([#9828](https://github.com/paritytech/parity-ethereum/pull/9828))
|
||||
- Support MIX. ([#9767](https://github.com/paritytech/parity-ethereum/pull/9767))
|
||||
- Ci: remove failing tests for android, windows, and macos ([#9788](https://github.com/paritytech/parity-ethereum/pull/9788))
|
||||
- Implement NoProof for json tests and update tests reference (replaces [#9744](https://github.com/paritytech/parity-ethereum/issues/9744)) ([#9814](https://github.com/paritytech/parity-ethereum/pull/9814))
|
||||
- Chore(bump regex) ([#9842](https://github.com/paritytech/parity-ethereum/pull/9842))
|
||||
- Ignore global cache for patched accounts ([#9752](https://github.com/paritytech/parity-ethereum/pull/9752))
|
||||
- Move state root verification before gas used ([#9841](https://github.com/paritytech/parity-ethereum/pull/9841))
|
||||
- Fix(docker-aarch64) : cross-compile config ([#9798](https://github.com/paritytech/parity-ethereum/pull/9798))
|
||||
- Version: bump nightly to 2.3.0 ([#9819](https://github.com/paritytech/parity-ethereum/pull/9819))
|
||||
- Tests modification for windows CI ([#9671](https://github.com/paritytech/parity-ethereum/pull/9671))
|
||||
- Eip-712 implementation ([#9631](https://github.com/paritytech/parity-ethereum/pull/9631))
|
||||
- Fix typo ([#9826](https://github.com/paritytech/parity-ethereum/pull/9826))
|
||||
- Clean up serde rename and use rename_all = camelCase when possible ([#9823](https://github.com/paritytech/parity-ethereum/pull/9823))
|
||||
## Parity-Ethereum [v2.4.2](https://github.com/paritytech/parity-ethereum/releases/tag/v2.4.2) (2019-03-20)
|
||||
|
||||
Parity-Ethereum 2.4.2-beta is a bugfix release that improves performance and stability.
|
||||
|
||||
The full list of included changes:
|
||||
- 2.4.2 beta backports ([#10488](https://github.com/paritytech/parity-ethereum/pull/10488))
|
||||
- Version: bump beta
|
||||
- Сaching through docker volume ([#10477](https://github.com/paritytech/parity-ethereum/pull/10477))
|
||||
- fix win&mac build ([#10486](https://github.com/paritytech/parity-ethereum/pull/10486))
|
||||
- fix(extract `timestamp_checked_add` as lib) ([#10383](https://github.com/paritytech/parity-ethereum/pull/10383))
|
||||
|
||||
## Parity-Ethereum [v2.4.1](https://github.com/paritytech/parity-ethereum/releases/tag/v2.4.1) (2019-03-19)
|
||||
|
||||
Parity-Ethereum 2.4.1-beta is a bugfix release that improves performance and stability.
|
||||
|
||||
The full list of included changes:
|
||||
- 2.4.1 beta backports ([#10471](https://github.com/paritytech/parity-ethereum/pull/10471))
|
||||
- Version: bump beta
|
||||
- Implement parity_versionInfo & parity_setChain on LC; fix parity_setChain ([#10312](https://github.com/paritytech/parity-ethereum/pull/10312))
|
||||
- CI publish to aws ([#10446](https://github.com/paritytech/parity-ethereum/pull/10446))
|
||||
- CI aws git checkout ([#10451](https://github.com/paritytech/parity-ethereum/pull/10451))
|
||||
- Revert "CI aws git checkout ([#10451](https://github.com/paritytech/parity-ethereum/pull/10451))" ([#10456](https://github.com/paritytech/parity-ethereum/pull/10456))
|
||||
- Tests parallelized ([#10452](https://github.com/paritytech/parity-ethereum/pull/10452))
|
||||
- Ensure static validator set changes are recognized ([#10467](https://github.com/paritytech/parity-ethereum/pull/10467))
|
||||
|
||||
## Parity-Ethereum [v2.4.0](https://github.com/paritytech/parity-ethereum/releases/tag/v2.4.0) (2019-02-25)
|
||||
|
||||
Parity-Ethereum 2.4.0-beta is our trifortnightly minor version release coming with a lot of new features as well as bugfixes and performance improvements.
|
||||
|
||||
Notable changes:
|
||||
- Account management is now deprecated ([#10213](https://github.com/paritytech/parity-ethereum/pull/10213))
|
||||
- Local accounts can now be specified via CLI ([#9960](https://github.com/paritytech/parity-ethereum/pull/9960))
|
||||
- Chains can now be reset to a particular block via CLI ([#9782](https://github.com/paritytech/parity-ethereum/pull/9782))
|
||||
- Ethash now additionally implements ProgPoW ([#9762](https://github.com/paritytech/parity-ethereum/pull/9762))
|
||||
- The `eip1283DisableTransition` flag was added to revert EIP-1283 ([#10214](https://github.com/paritytech/parity-ethereum/pull/10214))
|
||||
|
||||
The full list of included changes:
|
||||
- More Backports for Beta 2.4.0 ([#10431](https://github.com/paritytech/parity-ethereum/pull/10431))
|
||||
- Revert some changes, could be buggy ([#10399](https://github.com/paritytech/parity-ethereum/pull/10399))
|
||||
- Ci: clean up gitlab-ci.yml leftovers from previous merge ([#10429](https://github.com/paritytech/parity-ethereum/pull/10429))
|
||||
- 10000 > 5000 ([#10422](https://github.com/paritytech/parity-ethereum/pull/10422))
|
||||
- Fix underflow in pip, closes [#10419](https://github.com/paritytech/parity-ethereum/pull/10419) ([#10423](https://github.com/paritytech/parity-ethereum/pull/10423))
|
||||
- Fix panic when logging directory does not exist, closes [#10420](https://github.com/paritytech/parity-ethereum/pull/10420) ([#10424](https://github.com/paritytech/parity-ethereum/pull/10424))
|
||||
- Update hardcoded headers for Foundation, Ropsten, Kovan and Classic ([#10417](https://github.com/paritytech/parity-ethereum/pull/10417))
|
||||
- Backports for Beta 2.4.0 ([#10416](https://github.com/paritytech/parity-ethereum/pull/10416))
|
||||
- No-git for publish jobs, empty artifacts dir ([#10393](https://github.com/paritytech/parity-ethereum/pull/10393))
|
||||
- Snap: reenable i386, arm64, armhf architecture publishing ([#10386](https://github.com/paritytech/parity-ethereum/pull/10386))
|
||||
- Tx pool: always accept local transactions ([#10375](https://github.com/paritytech/parity-ethereum/pull/10375))
|
||||
- Fix to_pod storage trie value decoding ([#10368](https://github.com/paritytech/parity-ethereum/pull/10368))
|
||||
- Version: mark 2.4.0 beta
|
||||
- Update to latest mem-db, hash-db and trie-db. ([#10314](https://github.com/paritytech/parity-ethereum/pull/10314))
|
||||
- Tx pool: always accept local transactions ([#10375](https://github.com/paritytech/parity-ethereum/pull/10375))
|
||||
- Fix(trace_main! macro): don't re-export ([#10384](https://github.com/paritytech/parity-ethereum/pull/10384))
|
||||
- Exchanged old(azure) bootnodes with new(ovh) ones ([#10309](https://github.com/paritytech/parity-ethereum/pull/10309))
|
||||
- Ethash: implement Progpow ([#9762](https://github.com/paritytech/parity-ethereum/pull/9762))
|
||||
- Snap: add the removable-media plug ([#10377](https://github.com/paritytech/parity-ethereum/pull/10377))
|
||||
- Add message to IO errors ([#10324](https://github.com/paritytech/parity-ethereum/pull/10324))
|
||||
- Chore(bump parity-daemonize): require rust >= 1.31 ([#10359](https://github.com/paritytech/parity-ethereum/pull/10359))
|
||||
- Secretstore: use in-memory transport in cluster tests ([#9850](https://github.com/paritytech/parity-ethereum/pull/9850))
|
||||
- Add fields to `memzero`'s Cargo.toml ([#10362](https://github.com/paritytech/parity-ethereum/pull/10362))
|
||||
- Snap: release untagged versions from branches to the candidate snap channel ([#10357](https://github.com/paritytech/parity-ethereum/pull/10357))
|
||||
- Fix(compilation warns): `no-default-features` ([#10346](https://github.com/paritytech/parity-ethereum/pull/10346))
|
||||
- No volumes are needed, just run -v volume:/path/in/the/container ([#10345](https://github.com/paritytech/parity-ethereum/pull/10345))
|
||||
- Fixed misstype ([#10351](https://github.com/paritytech/parity-ethereum/pull/10351))
|
||||
- Snap: prefix version and populate candidate channel ([#10343](https://github.com/paritytech/parity-ethereum/pull/10343))
|
||||
- Bundle protocol and packet_id together in chain sync ([#10315](https://github.com/paritytech/parity-ethereum/pull/10315))
|
||||
- Role back docker build image and docker deploy image to ubuntu:xenial… ([#10338](https://github.com/paritytech/parity-ethereum/pull/10338))
|
||||
- Change docker image based on debian instead of ubuntu due to the chan… ([#10336](https://github.com/paritytech/parity-ethereum/pull/10336))
|
||||
- Don't add discovery initiators to the node table ([#10305](https://github.com/paritytech/parity-ethereum/pull/10305))
|
||||
- Fix(docker): fix not receives SIGINT ([#10059](https://github.com/paritytech/parity-ethereum/pull/10059))
|
||||
- Snap: official image / test ([#10168](https://github.com/paritytech/parity-ethereum/pull/10168))
|
||||
- Fix(add helper for timestamp overflows) ([#10330](https://github.com/paritytech/parity-ethereum/pull/10330))
|
||||
- Additional error for invalid gas ([#10327](https://github.com/paritytech/parity-ethereum/pull/10327))
|
||||
- Revive parity_setMinGasPrice RPC call ([#10294](https://github.com/paritytech/parity-ethereum/pull/10294))
|
||||
- Add Statetest support for Constantinople Fix ([#10323](https://github.com/paritytech/parity-ethereum/pull/10323))
|
||||
- Fix(parity-clib): grumbles that were not addressed in [#9920](https://github.com/paritytech/parity-ethereum/pull/9920) ([#10154](https://github.com/paritytech/parity-ethereum/pull/10154))
|
||||
- Fix(light-rpc): Make `light_sync` generic ([#10238](https://github.com/paritytech/parity-ethereum/pull/10238))
|
||||
- Fix publish job ([#10317](https://github.com/paritytech/parity-ethereum/pull/10317))
|
||||
- Secure WS-RPC: grant access to all apis ([#10246](https://github.com/paritytech/parity-ethereum/pull/10246))
|
||||
- Make specification of protocol in SyncRequester::send_request explicit ([#10295](https://github.com/paritytech/parity-ethereum/pull/10295))
|
||||
- Fix: parity-clib/examples/cpp/CMakeLists.txt ([#10313](https://github.com/paritytech/parity-ethereum/pull/10313))
|
||||
- Ci optimizations ([#10297](https://github.com/paritytech/parity-ethereum/pull/10297))
|
||||
- Increase number of requested block bodies in chain sync ([#10247](https://github.com/paritytech/parity-ethereum/pull/10247))
|
||||
- Deprecate account management ([#10213](https://github.com/paritytech/parity-ethereum/pull/10213))
|
||||
- Properly handle check_epoch_end_signal errors ([#10015](https://github.com/paritytech/parity-ethereum/pull/10015))
|
||||
- Fix(osx and windows builds): bump parity-daemonize ([#10291](https://github.com/paritytech/parity-ethereum/pull/10291))
|
||||
- Add missing step for Using `systemd` service file ([#10175](https://github.com/paritytech/parity-ethereum/pull/10175))
|
||||
- Call private contract methods from another private contract (read-onl… ([#10086](https://github.com/paritytech/parity-ethereum/pull/10086))
|
||||
- Update ring to 0.14 ([#10262](https://github.com/paritytech/parity-ethereum/pull/10262))
|
||||
- Fix(secret-store): deprecation warning ([#10301](https://github.com/paritytech/parity-ethereum/pull/10301))
|
||||
- Update to jsonrpc-derive 10.0.2, fixes aliases bug ([#10300](https://github.com/paritytech/parity-ethereum/pull/10300))
|
||||
- Convert to jsonrpc-derive, use jsonrpc-* from crates.io ([#10298](https://github.com/paritytech/parity-ethereum/pull/10298))
|
||||
- Fix Windows build ([#10284](https://github.com/paritytech/parity-ethereum/pull/10284))
|
||||
- Don't run the CPP example on CI ([#10285](https://github.com/paritytech/parity-ethereum/pull/10285))
|
||||
- Additional tests for uint deserialization. ([#10279](https://github.com/paritytech/parity-ethereum/pull/10279))
|
||||
- Prevent silent errors in daemon mode ([#10007](https://github.com/paritytech/parity-ethereum/pull/10007))
|
||||
- Fix join-set test to be deterministic. ([#10263](https://github.com/paritytech/parity-ethereum/pull/10263))
|
||||
- Update CHANGELOG-2.2.md ([#10254](https://github.com/paritytech/parity-ethereum/pull/10254))
|
||||
- Macos heapsize force jemalloc ([#10234](https://github.com/paritytech/parity-ethereum/pull/10234))
|
||||
- Allow specifying local accounts via CLI ([#9960](https://github.com/paritytech/parity-ethereum/pull/9960))
|
||||
- Take in account zero gas price certification when doing transact_cont… ([#10232](https://github.com/paritytech/parity-ethereum/pull/10232))
|
||||
- Update CHANGELOG.md ([#10249](https://github.com/paritytech/parity-ethereum/pull/10249))
|
||||
- Fix typo: CHANGELOG-2.1 -> CHANGELOG-2.2 ([#10233](https://github.com/paritytech/parity-ethereum/pull/10233))
|
||||
- Update copyright year to 2019. ([#10181](https://github.com/paritytech/parity-ethereum/pull/10181))
|
||||
- Fixed: types::transaction::SignedTransaction; ([#10229](https://github.com/paritytech/parity-ethereum/pull/10229))
|
||||
- Fix(ManageNetwork): replace Range with RangeInclusive ([#10209](https://github.com/paritytech/parity-ethereum/pull/10209))
|
||||
- Import rpc transactions sequentially ([#10051](https://github.com/paritytech/parity-ethereum/pull/10051))
|
||||
- Enable St-Peters-Fork ("Constantinople Fix") ([#10223](https://github.com/paritytech/parity-ethereum/pull/10223))
|
||||
- Add EIP-1283 disable transition ([#10214](https://github.com/paritytech/parity-ethereum/pull/10214))
|
||||
- Echo CORS request headers by default ([#10221](https://github.com/paritytech/parity-ethereum/pull/10221))
|
||||
- Happy New Year! ([#10211](https://github.com/paritytech/parity-ethereum/pull/10211))
|
||||
- Perform stripping during build ([#10208](https://github.com/paritytech/parity-ethereum/pull/10208))
|
||||
- Remove CallContract and RegistryInfo re-exports from `ethcore/client` ([#10205](https://github.com/paritytech/parity-ethereum/pull/10205))
|
||||
- Extract CallContract and RegistryInfo traits into their own crate ([#10178](https://github.com/paritytech/parity-ethereum/pull/10178))
|
||||
- Update the changelogs for 2.1.11, 2.2.6, 2.2.7, and 2.3.0 ([#10197](https://github.com/paritytech/parity-ethereum/pull/10197))
|
||||
- Cancel Constantinople HF on POA Core ([#10198](https://github.com/paritytech/parity-ethereum/pull/10198))
|
||||
- Adds cli interface to allow reseting chain to a particular block ([#9782](https://github.com/paritytech/parity-ethereum/pull/9782))
|
||||
- Run all `igd` methods in its own thread ([#10195](https://github.com/paritytech/parity-ethereum/pull/10195))
|
||||
- Pull constantinople on ethereum network ([#10189](https://github.com/paritytech/parity-ethereum/pull/10189))
|
||||
- Update for Android cross-compilation. ([#10180](https://github.com/paritytech/parity-ethereum/pull/10180))
|
||||
- Version: bump fork blocks for kovan and foundation ([#10186](https://github.com/paritytech/parity-ethereum/pull/10186))
|
||||
- Handle the case for contract creation on an empty but exist account w… ([#10065](https://github.com/paritytech/parity-ethereum/pull/10065))
|
||||
- Align personal_unlockAccount behaviour when permanent unlock is disab… ([#10060](https://github.com/paritytech/parity-ethereum/pull/10060))
|
||||
- Drop `runtime` after others (especially `ws_server`) ([#10179](https://github.com/paritytech/parity-ethereum/pull/10179))
|
||||
- Version: bump nightly to 2.4 ([#10165](https://github.com/paritytech/parity-ethereum/pull/10165))
|
||||
- Skip locking in statedb for non-canon blocks ([#10141](https://github.com/paritytech/parity-ethereum/pull/10141))
|
||||
- Remove reference to ui-interface command-line option ([#10170](https://github.com/paritytech/parity-ethereum/pull/10170))
|
||||
- Fix [#9822](https://github.com/paritytech/parity-ethereum/pull/9822): trace_filter does not return failed contract creation ([#10140](https://github.com/paritytech/parity-ethereum/pull/10140))
|
||||
- Fix _cannot recursively call into `Core`_ issue ([#10144](https://github.com/paritytech/parity-ethereum/pull/10144))
|
||||
- Fix(whisper): correct PoW calculation ([#10166](https://github.com/paritytech/parity-ethereum/pull/10166))
|
||||
- Bump JSON-RPC ([#10151](https://github.com/paritytech/parity-ethereum/pull/10151))
|
||||
- Ping nodes from discovery ([#10167](https://github.com/paritytech/parity-ethereum/pull/10167))
|
||||
- Fix(android): remove dependency to libusb ([#10161](https://github.com/paritytech/parity-ethereum/pull/10161))
|
||||
- Refactor(trim_right_matches -> trim_end_matches) ([#10159](https://github.com/paritytech/parity-ethereum/pull/10159))
|
||||
- Merge Machine and WithRewards ([#10071](https://github.com/paritytech/parity-ethereum/pull/10071))
|
||||
|
||||
## Previous releases
|
||||
|
||||
- [CHANGELOG-2.2](docs/CHANGELOG-2.2.md) (_stable_)
|
||||
- [CHANGELOG-2.3](docs/CHANGELOG-2.3.md) (_stable_)
|
||||
- [CHANGELOG-2.2](docs/CHANGELOG-2.2.md) (EOL: 2019-02-25)
|
||||
- [CHANGELOG-2.1](docs/CHANGELOG-2.1.md) (EOL: 2019-01-16)
|
||||
- [CHANGELOG-2.0](docs/CHANGELOG-2.0.md) (EOL: 2018-11-15)
|
||||
- [CHANGELOG-1.11](docs/CHANGELOG-1.11.md) (EOL: 2018-09-19)
|
||||
|
||||
703
Cargo.lock
generated
703
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
description = "Parity Ethereum client"
|
||||
name = "parity-ethereum"
|
||||
# NOTE Make sure to update util/version/Cargo.toml as well
|
||||
version = "2.4.0"
|
||||
version = "2.5.1"
|
||||
license = "GPL-3.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
@@ -138,7 +138,8 @@ members = [
|
||||
"util/triehash-ethereum",
|
||||
"util/keccak-hasher",
|
||||
"util/patricia-trie-ethereum",
|
||||
"util/fastmap"
|
||||
"util/fastmap",
|
||||
"util/time-utils"
|
||||
]
|
||||
|
||||
[patch.crates-io]
|
||||
|
||||
@@ -7,6 +7,7 @@ name = "cli-signer"
|
||||
version = "1.4.0"
|
||||
|
||||
[dependencies]
|
||||
ethereum-types = "0.4"
|
||||
futures = "0.1"
|
||||
rpassword = "1.0"
|
||||
parity-rpc = { path = "../rpc" }
|
||||
|
||||
@@ -7,6 +7,7 @@ name = "parity-rpc-client"
|
||||
version = "1.4.0"
|
||||
|
||||
[dependencies]
|
||||
ethereum-types = "0.4"
|
||||
futures = "0.1"
|
||||
log = "0.4"
|
||||
serde = "1.0"
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
pub mod client;
|
||||
pub mod signer_client;
|
||||
|
||||
extern crate ethereum_types;
|
||||
extern crate futures;
|
||||
extern crate jsonrpc_core;
|
||||
extern crate jsonrpc_ws_server as ws;
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use client::{Rpc, RpcError};
|
||||
use rpc::signer::{ConfirmationRequest, TransactionModification, U256, TransactionCondition};
|
||||
use ethereum_types::U256;
|
||||
use rpc::signer::{ConfirmationRequest, TransactionModification, TransactionCondition};
|
||||
use serde;
|
||||
use serde_json::{Value as JsonValue, to_value};
|
||||
use std::path::PathBuf;
|
||||
|
||||
@@ -14,13 +14,15 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
extern crate ethereum_types;
|
||||
extern crate futures;
|
||||
extern crate rpassword;
|
||||
|
||||
extern crate parity_rpc as rpc;
|
||||
extern crate parity_rpc_client as client;
|
||||
|
||||
use rpc::signer::{U256, ConfirmationRequest};
|
||||
use ethereum_types::U256;
|
||||
use rpc::signer::ConfirmationRequest;
|
||||
use client::signer_client::SignerRpc;
|
||||
use std::io::{Write, BufRead, BufReader, stdout, stdin};
|
||||
use std::path::PathBuf;
|
||||
|
||||
@@ -1,3 +1,78 @@
|
||||
Note: Parity Ethereum 2.2 reached End-of-Life on 2019-02-25 (EOL).
|
||||
|
||||
## Parity-Ethereum [v2.2.11](https://github.com/paritytech/parity-ethereum/releases/tag/v2.2.11) (2019-02-21)
|
||||
|
||||
Parity-Ethereum 2.2.11-stable is a maintenance release that fixes snap and docker installations.
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- Stable: snap: release untagged versions from branches to the candidate ([#10357](https://github.com/paritytech/parity-ethereum/pull/10357)) ([#10372](https://github.com/paritytech/parity-ethereum/pull/10372))
|
||||
- Snap: release untagged versions from branches to the candidate snap channel ([#10357](https://github.com/paritytech/parity-ethereum/pull/10357))
|
||||
- Snap: add the removable-media plug ([#10377](https://github.com/paritytech/parity-ethereum/pull/10377))
|
||||
- Exchanged old(azure) bootnodes with new(ovh) ones ([#10309](https://github.com/paritytech/parity-ethereum/pull/10309))
|
||||
- Stable Backports ([#10353](https://github.com/paritytech/parity-ethereum/pull/10353))
|
||||
- Version: bump stable to 2.2.11
|
||||
- Snap: prefix version and populate candidate channel ([#10343](https://github.com/paritytech/parity-ethereum/pull/10343))
|
||||
- Snap: populate candidate releases with beta snaps to avoid stale channel
|
||||
- Snap: prefix version with v*
|
||||
- No volumes are needed, just run -v volume:/path/in/the/container ([#10345](https://github.com/paritytech/parity-ethereum/pull/10345))
|
||||
|
||||
## Parity-Ethereum [v2.2.10](https://github.com/paritytech/parity-ethereum/releases/tag/v2.2.10) (2019-02-13)
|
||||
|
||||
Parity-Ethereum 2.2.10-stable is a security-relevant release. A bug in the JSONRPC-deserialization module can cause crashes of all versions of Parity Ethereum nodes if an attacker is able to submit a specially-crafted RPC to certain publicly available endpoints.
|
||||
|
||||
- https://www.parity.io/new-parity-ethereum-update-fixes-several-rpc-vulnerabilities/
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- Additional error for invalid gas ([#10327](https://github.com/paritytech/parity-ethereum/pull/10327)) ([#10329](https://github.com/paritytech/parity-ethereum/pull/10329))
|
||||
- Backports for Stable 2.2.10 ([#10332](https://github.com/paritytech/parity-ethereum/pull/10332))
|
||||
- fix(docker-aarch64) : cross-compile config ([#9798](https://github.com/paritytech/parity-ethereum/pull/9798))
|
||||
- import rpc transactions sequentially ([#10051](https://github.com/paritytech/parity-ethereum/pull/10051))
|
||||
- fix(docker): fix not receives SIGINT ([#10059](https://github.com/paritytech/parity-ethereum/pull/10059))
|
||||
- snap: official image / test ([#10168](https://github.com/paritytech/parity-ethereum/pull/10168))
|
||||
- perform stripping during build ([#10208](https://github.com/paritytech/parity-ethereum/pull/10208))
|
||||
- Additional tests for uint/hash/bytes deserialization. ([#10279](https://github.com/paritytech/parity-ethereum/pull/10279))
|
||||
- Don't run the CPP example on CI ([#10285](https://github.com/paritytech/parity-ethereum/pull/10285))
|
||||
- CI optimizations ([#10297](https://github.com/paritytech/parity-ethereum/pull/10297))
|
||||
- fix publish job ([#10317](https://github.com/paritytech/parity-ethereum/pull/10317))
|
||||
- Add Statetest support for Constantinople Fix ([#10323](https://github.com/paritytech/parity-ethereum/pull/10323))
|
||||
- Add helper for Timestamp overflows ([#10330](https://github.com/paritytech/parity-ethereum/pull/10330))
|
||||
- Don't add discovery initiators to the node table ([#10305](https://github.com/paritytech/parity-ethereum/pull/10305))
|
||||
- change docker image based on debian instead of ubuntu due to the chan ([#10336](https://github.com/paritytech/parity-ethereum/pull/10336))
|
||||
- role back docker build image and docker deploy image to ubuntu:xenial based ([#10338](https://github.com/paritytech/parity-ethereum/pull/10338))
|
||||
|
||||
## Parity-Ethereum [v2.2.9](https://github.com/paritytech/parity-ethereum/releases/tag/v2.2.9) (2019-02-03)
|
||||
|
||||
Parity-Ethereum 2.2.9-stable is a security-relevant release. A bug in the JSONRPC-deserialization module can cause crashes of all versions of Parity Ethereum nodes if an attacker is able to submit a specially-crafted RPC to certain publicly available endpoints.
|
||||
|
||||
- https://www.parity.io/security-alert-parity-ethereum-03-02/
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- Additional tests for uint deserialization. ([#10279](https://github.com/paritytech/parity-ethereum/pull/10279)) ([#10281](https://github.com/paritytech/parity-ethereum/pull/10281))
|
||||
- Version: bump stable to 2.2.9 ([#10282](https://github.com/paritytech/parity-ethereum/pull/10282))
|
||||
|
||||
## Parity-Ethereum [v2.2.8](https://github.com/paritytech/parity-ethereum/releases/tag/v2.2.8) (2019-02-01)
|
||||
|
||||
Parity-Ethereum 2.2.8-stable is a consensus-relevant release that enables _St. Petersfork_ on:
|
||||
|
||||
- Ethereum Block `7280000` (along with Constantinople)
|
||||
- Kovan Block `10255201`
|
||||
- Ropsten Block `4939394`
|
||||
- POA Sokol Block `7026400`
|
||||
|
||||
In addition to this, Constantinople is cancelled for the POA Core network. Upgrading is mandatory for clients on any of these chains.
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- Backports for stable 2.2.8 ([#10224](https://github.com/paritytech/parity-ethereum/pull/10224))
|
||||
- Update for Android cross-compilation. ([#10180](https://github.com/paritytech/parity-ethereum/pull/10180))
|
||||
- Cancel Constantinople HF on POA Core ([#10198](https://github.com/paritytech/parity-ethereum/pull/10198))
|
||||
- Add EIP-1283 disable transition ([#10214](https://github.com/paritytech/parity-ethereum/pull/10214))
|
||||
- Enable St-Peters-Fork ("Constantinople Fix") ([#10223](https://github.com/paritytech/parity-ethereum/pull/10223))
|
||||
- Stable: Macos heapsize force jemalloc ([#10234](https://github.com/paritytech/parity-ethereum/pull/10234)) ([#10258](https://github.com/paritytech/parity-ethereum/pull/10258))
|
||||
|
||||
## Parity-Ethereum [v2.2.7](https://github.com/paritytech/parity-ethereum/releases/tag/v2.2.7) (2019-01-15)
|
||||
|
||||
Parity-Ethereum 2.2.7-stable is a consensus-relevant security release that reverts Constantinople on the Ethereum network. Upgrading is mandatory for Ethereum, and strongly recommended for other networks.
|
||||
|
||||
288
docs/CHANGELOG-2.3.md
Normal file
288
docs/CHANGELOG-2.3.md
Normal file
@@ -0,0 +1,288 @@
|
||||
## Parity-Ethereum [v2.3.8](https://github.com/paritytech/parity-ethereum/releases/tag/v2.3.8) (2019-03-22)
|
||||
|
||||
Parity-Ethereum 2.3.8-stable is a bugfix release that improves performance and stability. This patch release contains a critical bug fix where serving light clients previously led to client crashes. Upgrading is highly recommended.
|
||||
|
||||
The full list of included changes:
|
||||
- 2.3.8 stable backports ([#10507](https://github.com/paritytech/parity-ethereum/pull/10507))
|
||||
- Version: bump stable
|
||||
- Add additional request tests ([#10503](https://github.com/paritytech/parity-ethereum/pull/10503))
|
||||
|
||||
## Parity-Ethereum [v2.3.7](https://github.com/paritytech/parity-ethereum/releases/tag/v2.3.7) (2019-03-20)
|
||||
|
||||
Parity-Ethereum 2.3.7-stable is a bugfix release that improves performance and stability.
|
||||
|
||||
The full list of included changes:
|
||||
- 2.3.7 stable backports ([#10487](https://github.com/paritytech/parity-ethereum/pull/10487))
|
||||
- Version: bump stable
|
||||
- Сaching through docker volume ([#10477](https://github.com/paritytech/parity-ethereum/pull/10477))
|
||||
- fix win&mac build ([#10486](https://github.com/paritytech/parity-ethereum/pull/10486))
|
||||
- fix(extract `timestamp_checked_add` as lib) ([#10383](https://github.com/paritytech/parity-ethereum/pull/10383))
|
||||
|
||||
## Parity-Ethereum [v2.3.6](https://github.com/paritytech/parity-ethereum/releases/tag/v2.3.6) (2019-03-19)
|
||||
|
||||
Parity-Ethereum 2.3.6-stable is a bugfix release that improves performance and stability.
|
||||
|
||||
The full list of included changes:
|
||||
- 2.3.6 stable backports ([#10470](https://github.com/paritytech/parity-ethereum/pull/10470))
|
||||
- Version: bump stable
|
||||
- CI publish to aws ([#10446](https://github.com/paritytech/parity-ethereum/pull/10446))
|
||||
- Ensure static validator set changes are recognized ([#10467](https://github.com/paritytech/parity-ethereum/pull/10467))
|
||||
- CI aws git checkout ([#10451](https://github.com/paritytech/parity-ethereum/pull/10451))
|
||||
- Revert "CI aws git checkout ([#10451](https://github.com/paritytech/parity-ethereum/pull/10451))" ([#10456](https://github.com/paritytech/parity-ethereum/pull/10456))
|
||||
- Tests parallelized ([#10452](https://github.com/paritytech/parity-ethereum/pull/10452))
|
||||
|
||||
## Parity-Ethereum [v2.3.5](https://github.com/paritytech/parity-ethereum/releases/tag/v2.3.5) (2019-02-25)
|
||||
|
||||
Parity-Ethereum 2.3.5-stable is a bugfix release that improves performance and stability.
|
||||
|
||||
Note, all 2.2 releases and older are now unsupported and upgrading is recommended.
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- More Backports for Stable 2.3.5 ([#10430](https://github.com/paritytech/parity-ethereum/pull/10430))
|
||||
- Revert some changes, could be buggy ([#10399](https://github.com/paritytech/parity-ethereum/pull/10399))
|
||||
- Ci: clean up gitlab-ci.yml leftovers from previous merge ([#10429](https://github.com/paritytech/parity-ethereum/pull/10429))
|
||||
- 10000 > 5000 ([#10422](https://github.com/paritytech/parity-ethereum/pull/10422))
|
||||
- Fix underflow in pip, closes [#10419](https://github.com/paritytech/parity-ethereum/pull/10419) ([#10423](https://github.com/paritytech/parity-ethereum/pull/10423))
|
||||
- Fix panic when logging directory does not exist, closes [#10420](https://github.com/paritytech/parity-ethereum/pull/10420) ([#10424](https://github.com/paritytech/parity-ethereum/pull/10424))
|
||||
- Update hardcoded headers for Foundation, Ropsten, Kovan and Classic ([#10417](https://github.com/paritytech/parity-ethereum/pull/10417))
|
||||
- Backports for Stable 2.3.5 ([#10414](https://github.com/paritytech/parity-ethereum/pull/10414))
|
||||
- No-git for publish jobs, empty artifacts dir ([#10393](https://github.com/paritytech/parity-ethereum/pull/10393))
|
||||
- Snap: reenable i386, arm64, armhf architecture publishing ([#10386](https://github.com/paritytech/parity-ethereum/pull/10386))
|
||||
- Tx pool: always accept local transactions ([#10375](https://github.com/paritytech/parity-ethereum/pull/10375))
|
||||
- Fix to_pod storage trie value decoding ([#10368)](https://github.com/paritytech/parity-ethereum/pull/10368))
|
||||
- Version: mark 2.3.5 as stable
|
||||
|
||||
## Parity-Ethereum [v2.3.4](https://github.com/paritytech/parity-ethereum/releases/tag/v2.3.4) (2019-02-21)
|
||||
|
||||
Parity-Ethereum 2.3.4-beta is a maintenance release that fixes snap and docker installations.
|
||||
|
||||
The full list of included changes:
|
||||
- Beta: snap: release untagged versions from branches to the candidate ([#10357](https://github.com/paritytech/parity-ethereum/pull/10357)) ([#10373](https://github.com/paritytech/parity-ethereum/pull/10373))
|
||||
- Snap: release untagged versions from branches to the candidate snap channel ([#10357](https://github.com/paritytech/parity-ethereum/pull/10357))
|
||||
- Snap: add the removable-media plug ([#10377](https://github.com/paritytech/parity-ethereum/pull/10377))
|
||||
- Exchanged old(azure) bootnodes with new(ovh) ones ([#10309](https://github.com/paritytech/parity-ethereum/pull/10309))
|
||||
- Beta Backports ([#10354](https://github.com/paritytech/parity-ethereum/pull/10354))
|
||||
- Version: bump beta to 2.3.4
|
||||
- Snap: prefix version and populate candidate channel ([#10343](https://github.com/paritytech/parity-ethereum/pull/10343))
|
||||
- Snap: populate candidate releases with beta snaps to avoid stale channel
|
||||
- Snap: prefix version with v*
|
||||
- No volumes are needed, just run -v volume:/path/in/the/container ([#10345](https://github.com/paritytech/parity-ethereum/pull/10345))
|
||||
|
||||
## Parity-Ethereum [v2.3.3](https://github.com/paritytech/parity-ethereum/releases/tag/v2.3.3) (2019-02-13)
|
||||
|
||||
Parity-Ethereum 2.3.3-beta is a security-relevant release. A bug in the JSONRPC-deserialization module can cause crashes of all versions of Parity Ethereum nodes if an attacker is able to submit a specially-crafted RPC to certain publicly available endpoints.
|
||||
|
||||
- https://www.parity.io/new-parity-ethereum-update-fixes-several-rpc-vulnerabilities/
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- Additional error for invalid gas ([#10327](https://github.com/paritytech/parity-ethereum/pull/10327)) ([#10328](https://github.com/paritytech/parity-ethereum/pull/10328))
|
||||
- Backports for Beta 2.3.3 ([#10333](https://github.com/paritytech/parity-ethereum/pull/10333))
|
||||
- Properly handle check_epoch_end_signal errors ([#10015](https://github.com/paritytech/parity-ethereum/pull/10015))
|
||||
- import rpc transactions sequentially ([#10051](https://github.com/paritytech/parity-ethereum/pull/10051))
|
||||
- fix(docker): fix not receives SIGINT ([#10059](https://github.com/paritytech/parity-ethereum/pull/10059))
|
||||
- snap: official image / test ([#10168](https://github.com/paritytech/parity-ethereum/pull/10168))
|
||||
- Extract CallContract and RegistryInfo traits into their own crate ([#10178](https://github.com/paritytech/parity-ethereum/pull/10178))
|
||||
- perform stripping during build ([#10208](https://github.com/paritytech/parity-ethereum/pull/10208))
|
||||
- Remove CallContract and RegistryInfo re-exports from `ethcore/client` ([#10205](https://github.com/paritytech/parity-ethereum/pull/10205))
|
||||
- fixed: types::transaction::SignedTransaction; ([#10229](https://github.com/paritytech/parity-ethereum/pull/10229))
|
||||
- Additional tests for uint/hash/bytes deserialization. ([#10279](https://github.com/paritytech/parity-ethereum/pull/10279))
|
||||
- Fix Windows build ([#10284](https://github.com/paritytech/parity-ethereum/pull/10284))
|
||||
- Don't run the CPP example on CI ([#10285](https://github.com/paritytech/parity-ethereum/pull/10285))
|
||||
- CI optimizations ([#10297](https://github.com/paritytech/parity-ethereum/pull/10297))
|
||||
- fix publish job ([#10317](https://github.com/paritytech/parity-ethereum/pull/10317))
|
||||
- Add Statetest support for Constantinople Fix ([#10323](https://github.com/paritytech/parity-ethereum/pull/10323))
|
||||
- Add helper for Timestamp overflows ([#10330](https://github.com/paritytech/parity-ethereum/pull/10330))
|
||||
- Don't add discovery initiators to the node table ([#10305](https://github.com/paritytech/parity-ethereum/pull/10305))
|
||||
- change docker image based on debian instead of ubuntu due to the chan ([#10336](https://github.com/paritytech/parity-ethereum/pull/10336))
|
||||
- role back docker build image and docker deploy image to ubuntu:xenial based ([#10338](https://github.com/paritytech/parity-ethereum/pull/10338))
|
||||
|
||||
## Parity-Ethereum [v2.3.2](https://github.com/paritytech/parity-ethereum/releases/tag/v2.3.2) (2019-02-03)
|
||||
|
||||
Parity-Ethereum 2.3.2-stable is a security-relevant release. A bug in the JSONRPC-deserialization module can cause crashes of all versions of Parity Ethereum nodes if an attacker is able to submit a specially-crafted RPC to certain publicly available endpoints.
|
||||
|
||||
- https://www.parity.io/security-alert-parity-ethereum-03-02/
|
||||
|
||||
The full list of included changes:
|
||||
- Version: bump beta to 2.3.2 ([#10283](https://github.com/paritytech/parity-ethereum/pull/10283))
|
||||
- Additional tests for uint deserialization. ([#10279](https://github.com/paritytech/parity-ethereum/pull/10279)) ([#10280](https://github.com/paritytech/parity-ethereum/pull/10280))
|
||||
- Backport [#10285](https://github.com/paritytech/parity-ethereum/pull/10285) to beta ([#10286](https://github.com/paritytech/parity-ethereum/pull/10286))
|
||||
|
||||
## Parity-Ethereum [v2.3.1](https://github.com/paritytech/parity-ethereum/releases/tag/v2.3.1) (2019-02-01)
|
||||
|
||||
Parity-Ethereum 2.3.1-beta is a consensus-relevant release that enables _St. Petersfork_ on:
|
||||
|
||||
- Ethereum Block `7280000` (along with Constantinople)
|
||||
- Kovan Block `10255201`
|
||||
- Ropsten Block `4939394`
|
||||
- POA Sokol Block `7026400`
|
||||
|
||||
In addition to this, Constantinople is cancelled for the POA Core network. Upgrading is mandatory for clients on any of these chains.
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- Backports for beta 2.3.1 ([#10225](https://github.com/paritytech/parity-ethereum/pull/10225))
|
||||
- Fix _cannot recursively call into `Core`_ issue ([#10144](https://github.com/paritytech/parity-ethereum/pull/10144))
|
||||
- Update for Android cross-compilation. ([#10180](https://github.com/paritytech/parity-ethereum/pull/10180))
|
||||
- Fix _cannot recursively call into `Core`_ - Part 2 ([#10195](https://github.com/paritytech/parity-ethereum/pull/10195))
|
||||
- Cancel Constantinople HF on POA Core ([#10198](https://github.com/paritytech/parity-ethereum/pull/10198))
|
||||
- Add EIP-1283 disable transition ([#10214](https://github.com/paritytech/parity-ethereum/pull/10214))
|
||||
- Enable St-Peters-Fork ("Constantinople Fix") ([#10223](https://github.com/paritytech/parity-ethereum/pull/10223))
|
||||
- Beta: Macos heapsize force jemalloc ([#10234](https://github.com/paritytech/parity-ethereum/pull/10234)) ([#10259](https://github.com/paritytech/parity-ethereum/pull/10259))
|
||||
|
||||
## Parity-Ethereum [v2.3.0](https://github.com/paritytech/parity-ethereum/releases/tag/v2.3.0) (2019-01-16)
|
||||
|
||||
Parity-Ethereum 2.3.0-beta is a consensus-relevant security release that reverts Constantinople on the Ethereum network. Upgrading is mandatory for Ethereum, and strongly recommended for other networks.
|
||||
|
||||
- **Consensus** - Ethereum Network: Pull Constantinople protocol upgrade on Ethereum ([#10189](https://github.com/paritytech/parity-ethereum/pull/10189))
|
||||
- Read more: [Security Alert: Ethereum Constantinople Postponement](https://blog.ethereum.org/2019/01/15/security-alert-ethereum-constantinople-postponement/)
|
||||
- **Networking** - All networks: Ping nodes from discovery ([#10167](https://github.com/paritytech/parity-ethereum/pull/10167))
|
||||
- **Wasm** - Kovan Network: Update pwasm-utils to 0.6.1 ([#10134](https://github.com/paritytech/parity-ethereum/pull/10134))
|
||||
|
||||
Other notable changes:
|
||||
|
||||
- Existing blocks in the database are now kept when restoring a Snapshot. ([#8643](https://github.com/paritytech/parity-ethereum/pull/8643))
|
||||
- Block and transaction propagation is improved significantly. ([#9954](https://github.com/paritytech/parity-ethereum/pull/9954))
|
||||
- The ERC-191 Signed Data Standard is now supported by `personal_sign191`. ([#9701](https://github.com/paritytech/parity-ethereum/pull/9701))
|
||||
- Add support for ERC-191/712 `eth_signTypedData` as a standard for machine-verifiable and human-readable typed data signing with Ethereum keys. ([#9631](https://github.com/paritytech/parity-ethereum/pull/9631))
|
||||
- Add support for ERC-1186 `eth_getProof` ([#9001](https://github.com/paritytech/parity-ethereum/pull/9001))
|
||||
- Add experimental RPCs flag to enable ERC-191, ERC-712, and ERC-1186 APIs via `--jsonrpc-experimental` ([#9928](https://github.com/paritytech/parity-ethereum/pull/9928))
|
||||
- Make `CALLCODE` to trace value to be the code address. ([#9881](https://github.com/paritytech/parity-ethereum/pull/9881))
|
||||
|
||||
Configuration changes:
|
||||
|
||||
- The EIP-98 transition is now disabled by default. If you previously had no `eip98transition` specified in your chain specification, you would enable this now manually on block `0x0`. ([#9955](https://github.com/paritytech/parity-ethereum/pull/9955))
|
||||
- Also, unknown fields in chain specs are now rejected. ([#9972](https://github.com/paritytech/parity-ethereum/pull/9972))
|
||||
- The Tendermint engine was removed from Parity Ethereum and is no longer available and maintained. ([#9980](https://github.com/paritytech/parity-ethereum/pull/9980))
|
||||
- Ropsten testnet data and keys moved from `test/` to `ropsten/` subdir. To reuse your old keys and data either copy or symlink them to the new location. ([#10123](https://github.com/paritytech/parity-ethereum/pull/10123))
|
||||
- Strict empty steps validation ([#10041](https://github.com/paritytech/parity-ethereum/pull/10041))
|
||||
- If you have a chain with`empty_steps` already running, some blocks most likely contain non-strict entries (unordered or duplicated empty steps). In this release `strict_empty_steps_transition` is enabled by default at block `0x0` for any chain with `empty_steps`.
|
||||
- If your network uses `empty_steps` you **must** (A) plan a hard fork and change `strict_empty_steps_transition` to the desired fork block and (B) update the clients of the whole network to 2.2.7-stable / 2.3.0-beta. If for some reason you don't want to do this please set`strict_empty_steps_transition` to `0xfffffffff` to disable it.
|
||||
|
||||
_Note:_ This release marks Parity 2.3 as _beta_. All versions of Parity 2.2 are now considered _stable_.
|
||||
|
||||
The full list of included changes:
|
||||
|
||||
- Backports for 2.3.0 beta ([#10164](https://github.com/paritytech/parity-ethereum/pull/10164))
|
||||
- Snap: fix path in script ([#10157](https://github.com/paritytech/parity-ethereum/pull/10157))
|
||||
- Make sure parent block is not in importing queue when importing ancient blocks ([#10138](https://github.com/paritytech/parity-ethereum/pull/10138))
|
||||
- Ci: re-enable snap publishing ([#10142](https://github.com/paritytech/parity-ethereum/pull/10142))
|
||||
- Hf in POA Core (2019-01-18) - Constantinople ([#10155](https://github.com/paritytech/parity-ethereum/pull/10155))
|
||||
- Update EWF's tobalaba chainspec ([#10152](https://github.com/paritytech/parity-ethereum/pull/10152))
|
||||
- Replace ethcore-logger with env-logger. ([#10102](https://github.com/paritytech/parity-ethereum/pull/10102))
|
||||
- Finality: dont require chain head to be in the chain ([#10054](https://github.com/paritytech/parity-ethereum/pull/10054))
|
||||
- Remove caching for node connections ([#10143](https://github.com/paritytech/parity-ethereum/pull/10143))
|
||||
- Blooms file iterator empty on out of range position. ([#10145](https://github.com/paritytech/parity-ethereum/pull/10145))
|
||||
- Autogen docs for the "Configuring Parity Ethereum" wiki page. ([#10067](https://github.com/paritytech/parity-ethereum/pull/10067))
|
||||
- Misc: bump license header to 2019 ([#10135](https://github.com/paritytech/parity-ethereum/pull/10135))
|
||||
- Hide most of the logs from cpp example. ([#10139](https://github.com/paritytech/parity-ethereum/pull/10139))
|
||||
- Don't try to send oversized packets ([#10042](https://github.com/paritytech/parity-ethereum/pull/10042))
|
||||
- Private tx enabled flag added into STATUS packet ([#9999](https://github.com/paritytech/parity-ethereum/pull/9999))
|
||||
- Update pwasm-utils to 0.6.1 ([#10134](https://github.com/paritytech/parity-ethereum/pull/10134))
|
||||
- Extract blockchain from ethcore ([#10114](https://github.com/paritytech/parity-ethereum/pull/10114))
|
||||
- Ethcore: update hardcoded headers ([#10123](https://github.com/paritytech/parity-ethereum/pull/10123))
|
||||
- Identity fix ([#10128](https://github.com/paritytech/parity-ethereum/pull/10128))
|
||||
- Use LenCachingMutex to optimize verification. ([#10117](https://github.com/paritytech/parity-ethereum/pull/10117))
|
||||
- Pyethereum keystore support ([#9710](https://github.com/paritytech/parity-ethereum/pull/9710))
|
||||
- Bump rocksdb-sys to 0.5.5 ([#10124](https://github.com/paritytech/parity-ethereum/pull/10124))
|
||||
- Parity-clib: `async C bindings to RPC requests` + `subscribe/unsubscribe to websocket events` ([#9920](https://github.com/paritytech/parity-ethereum/pull/9920))
|
||||
- Refactor (hardware wallet) : reduce the number of threads ([#9644](https://github.com/paritytech/parity-ethereum/pull/9644))
|
||||
- Hf in POA Sokol (2019-01-04) ([#10077](https://github.com/paritytech/parity-ethereum/pull/10077))
|
||||
- Fix broken links ([#10119](https://github.com/paritytech/parity-ethereum/pull/10119))
|
||||
- Follow-up to [#10105](https://github.com/paritytech/parity-ethereum/issues/10105) ([#10107](https://github.com/paritytech/parity-ethereum/pull/10107))
|
||||
- Move EIP-712 crate back to parity-ethereum ([#10106](https://github.com/paritytech/parity-ethereum/pull/10106))
|
||||
- Move a bunch of stuff around ([#10101](https://github.com/paritytech/parity-ethereum/pull/10101))
|
||||
- Revert "Add --frozen when running cargo ([#10081](https://github.com/paritytech/parity-ethereum/pull/10081))" ([#10105](https://github.com/paritytech/parity-ethereum/pull/10105))
|
||||
- Fix left over small grumbles on whitespaces ([#10084](https://github.com/paritytech/parity-ethereum/pull/10084))
|
||||
- Add --frozen when running cargo ([#10081](https://github.com/paritytech/parity-ethereum/pull/10081))
|
||||
- Fix pubsub new_blocks notifications to include all blocks ([#9987](https://github.com/paritytech/parity-ethereum/pull/9987))
|
||||
- Update some dependencies for compilation with pc-windows-gnu ([#10082](https://github.com/paritytech/parity-ethereum/pull/10082))
|
||||
- Fill transaction hash on ethGetLog of light client. ([#9938](https://github.com/paritytech/parity-ethereum/pull/9938))
|
||||
- Update changelog update for 2.2.5-beta and 2.1.10-stable ([#10064](https://github.com/paritytech/parity-ethereum/pull/10064))
|
||||
- Implement len caching for parking_lot RwLock ([#10032](https://github.com/paritytech/parity-ethereum/pull/10032))
|
||||
- Update parking_lot to 0.7 ([#10050](https://github.com/paritytech/parity-ethereum/pull/10050))
|
||||
- Bump crossbeam. ([#10048](https://github.com/paritytech/parity-ethereum/pull/10048))
|
||||
- Ethcore: enable constantinople on ethereum ([#10031](https://github.com/paritytech/parity-ethereum/pull/10031))
|
||||
- Strict empty steps validation ([#10041](https://github.com/paritytech/parity-ethereum/pull/10041))
|
||||
- Center the Subtitle, use some CAPS ([#10034](https://github.com/paritytech/parity-ethereum/pull/10034))
|
||||
- Change test miner max memory to malloc reports. ([#10024](https://github.com/paritytech/parity-ethereum/pull/10024))
|
||||
- Sort the storage for private state ([#10018](https://github.com/paritytech/parity-ethereum/pull/10018))
|
||||
- Fix: test corpus_inaccessible panic ([#10019](https://github.com/paritytech/parity-ethereum/pull/10019))
|
||||
- Ci: move future releases to ethereum subdir on s3 ([#10017](https://github.com/paritytech/parity-ethereum/pull/10017))
|
||||
- Light(on_demand): decrease default time window to 10 secs ([#10016](https://github.com/paritytech/parity-ethereum/pull/10016))
|
||||
- Light client : failsafe crate (circuit breaker) ([#9790](https://github.com/paritytech/parity-ethereum/pull/9790))
|
||||
- Lencachingmutex ([#9988](https://github.com/paritytech/parity-ethereum/pull/9988))
|
||||
- Version and notification for private contract wrapper added ([#9761](https://github.com/paritytech/parity-ethereum/pull/9761))
|
||||
- Handle failing case for update account cache in require ([#9989](https://github.com/paritytech/parity-ethereum/pull/9989))
|
||||
- Add tokio runtime to ethcore io worker ([#9979](https://github.com/paritytech/parity-ethereum/pull/9979))
|
||||
- Move daemonize before creating account provider ([#10003](https://github.com/paritytech/parity-ethereum/pull/10003))
|
||||
- Docs: update changelogs ([#9990](https://github.com/paritytech/parity-ethereum/pull/9990))
|
||||
- Fix daemonize ([#10000](https://github.com/paritytech/parity-ethereum/pull/10000))
|
||||
- Fix Bloom migration ([#9992](https://github.com/paritytech/parity-ethereum/pull/9992))
|
||||
- Remove tendermint engine support ([#9980](https://github.com/paritytech/parity-ethereum/pull/9980))
|
||||
- Calculate gas for deployment transaction ([#9840](https://github.com/paritytech/parity-ethereum/pull/9840))
|
||||
- Fix unstable peers and slowness in sync ([#9967](https://github.com/paritytech/parity-ethereum/pull/9967))
|
||||
- Adds parity_verifySignature RPC method ([#9507](https://github.com/paritytech/parity-ethereum/pull/9507))
|
||||
- Improve block and transaction propagation ([#9954](https://github.com/paritytech/parity-ethereum/pull/9954))
|
||||
- Deny unknown fields for chainspec ([#9972](https://github.com/paritytech/parity-ethereum/pull/9972))
|
||||
- Fix docker build ([#9971](https://github.com/paritytech/parity-ethereum/pull/9971))
|
||||
- Ci: rearrange pipeline by logic ([#9970](https://github.com/paritytech/parity-ethereum/pull/9970))
|
||||
- Add changelogs for 2.0.9, 2.1.4, 2.1.6, and 2.2.1 ([#9963](https://github.com/paritytech/parity-ethereum/pull/9963))
|
||||
- Add Error message when sync is still in progress. ([#9475](https://github.com/paritytech/parity-ethereum/pull/9475))
|
||||
- Make CALLCODE to trace value to be the code address ([#9881](https://github.com/paritytech/parity-ethereum/pull/9881))
|
||||
- Fix light client informant while syncing ([#9932](https://github.com/paritytech/parity-ethereum/pull/9932))
|
||||
- Add a optional json dump state to evm-bin ([#9706](https://github.com/paritytech/parity-ethereum/pull/9706))
|
||||
- Disable EIP-98 transition by default ([#9955](https://github.com/paritytech/parity-ethereum/pull/9955))
|
||||
- Remove secret_store runtimes. ([#9888](https://github.com/paritytech/parity-ethereum/pull/9888))
|
||||
- Fix a deadlock ([#9952](https://github.com/paritytech/parity-ethereum/pull/9952))
|
||||
- Chore(eip712): remove unused `failure-derive` ([#9958](https://github.com/paritytech/parity-ethereum/pull/9958))
|
||||
- Do not use the home directory as the working dir in docker ([#9834](https://github.com/paritytech/parity-ethereum/pull/9834))
|
||||
- Prevent silent errors in daemon mode, closes [#9367](https://github.com/paritytech/parity-ethereum/issues/9367) ([#9946](https://github.com/paritytech/parity-ethereum/pull/9946))
|
||||
- Fix empty steps ([#9939](https://github.com/paritytech/parity-ethereum/pull/9939))
|
||||
- Adjust requests costs for light client ([#9925](https://github.com/paritytech/parity-ethereum/pull/9925))
|
||||
- Eip-1186: add `eth_getProof` RPC-Method ([#9001](https://github.com/paritytech/parity-ethereum/pull/9001))
|
||||
- Missing blocks in filter_changes RPC ([#9947](https://github.com/paritytech/parity-ethereum/pull/9947))
|
||||
- Allow rust-nightly builds fail in nightly builds ([#9944](https://github.com/paritytech/parity-ethereum/pull/9944))
|
||||
- Update eth-secp256k1 to include fix for BSDs ([#9935](https://github.com/paritytech/parity-ethereum/pull/9935))
|
||||
- Unbreak build on rust -stable ([#9934](https://github.com/paritytech/parity-ethereum/pull/9934))
|
||||
- Keep existing blocks when restoring a Snapshot ([#8643](https://github.com/paritytech/parity-ethereum/pull/8643))
|
||||
- Add experimental RPCs flag ([#9928](https://github.com/paritytech/parity-ethereum/pull/9928))
|
||||
- Clarify poll lifetime ([#9922](https://github.com/paritytech/parity-ethereum/pull/9922))
|
||||
- Docs(require rust 1.30) ([#9923](https://github.com/paritytech/parity-ethereum/pull/9923))
|
||||
- Use block header for building finality ([#9914](https://github.com/paritytech/parity-ethereum/pull/9914))
|
||||
- Simplify cargo audit ([#9918](https://github.com/paritytech/parity-ethereum/pull/9918))
|
||||
- Light-fetch: Differentiate between out-of-gas/manual throw and use required gas from response on failure ([#9824](https://github.com/paritytech/parity-ethereum/pull/9824))
|
||||
- Eip 191 ([#9701](https://github.com/paritytech/parity-ethereum/pull/9701))
|
||||
- Fix(logger): `reqwest` no longer a dependency ([#9908](https://github.com/paritytech/parity-ethereum/pull/9908))
|
||||
- Remove rust-toolchain file ([#9906](https://github.com/paritytech/parity-ethereum/pull/9906))
|
||||
- Foundation: 6692865, ropsten: 4417537, kovan: 9363457 ([#9907](https://github.com/paritytech/parity-ethereum/pull/9907))
|
||||
- Ethcore: use Machine::verify_transaction on parent block ([#9900](https://github.com/paritytech/parity-ethereum/pull/9900))
|
||||
- Chore(rpc-tests): remove unused rand ([#9896](https://github.com/paritytech/parity-ethereum/pull/9896))
|
||||
- Fix: Intermittent failing CI due to addr in use ([#9885](https://github.com/paritytech/parity-ethereum/pull/9885))
|
||||
- Chore(bump docopt): 0.8 -> 1.0 ([#9889](https://github.com/paritytech/parity-ethereum/pull/9889))
|
||||
- Use expect ([#9883](https://github.com/paritytech/parity-ethereum/pull/9883))
|
||||
- Use Weak reference in PubSubClient ([#9886](https://github.com/paritytech/parity-ethereum/pull/9886))
|
||||
- Ci: nuke the gitlab caches ([#9855](https://github.com/paritytech/parity-ethereum/pull/9855))
|
||||
- Remove unused code ([#9884](https://github.com/paritytech/parity-ethereum/pull/9884))
|
||||
- Fix json tracer overflow ([#9873](https://github.com/paritytech/parity-ethereum/pull/9873))
|
||||
- Allow to seal work on latest block ([#9876](https://github.com/paritytech/parity-ethereum/pull/9876))
|
||||
- Fix docker script ([#9854](https://github.com/paritytech/parity-ethereum/pull/9854))
|
||||
- Health endpoint ([#9847](https://github.com/paritytech/parity-ethereum/pull/9847))
|
||||
- Gitlab-ci: make android release build succeed ([#9743](https://github.com/paritytech/parity-ethereum/pull/9743))
|
||||
- Clean up existing benchmarks ([#9839](https://github.com/paritytech/parity-ethereum/pull/9839))
|
||||
- Update Callisto block reward code to support HF1 ([#9811](https://github.com/paritytech/parity-ethereum/pull/9811))
|
||||
- Option to disable keep alive for JSON-RPC http transport ([#9848](https://github.com/paritytech/parity-ethereum/pull/9848))
|
||||
- Classic.json Bootnode Update ([#9828](https://github.com/paritytech/parity-ethereum/pull/9828))
|
||||
- Support MIX. ([#9767](https://github.com/paritytech/parity-ethereum/pull/9767))
|
||||
- Ci: remove failing tests for android, windows, and macos ([#9788](https://github.com/paritytech/parity-ethereum/pull/9788))
|
||||
- Implement NoProof for json tests and update tests reference (replaces [#9744](https://github.com/paritytech/parity-ethereum/issues/9744)) ([#9814](https://github.com/paritytech/parity-ethereum/pull/9814))
|
||||
- Chore(bump regex) ([#9842](https://github.com/paritytech/parity-ethereum/pull/9842))
|
||||
- Ignore global cache for patched accounts ([#9752](https://github.com/paritytech/parity-ethereum/pull/9752))
|
||||
- Move state root verification before gas used ([#9841](https://github.com/paritytech/parity-ethereum/pull/9841))
|
||||
- Fix(docker-aarch64) : cross-compile config ([#9798](https://github.com/paritytech/parity-ethereum/pull/9798))
|
||||
- Version: bump nightly to 2.3.0 ([#9819](https://github.com/paritytech/parity-ethereum/pull/9819))
|
||||
- Tests modification for windows CI ([#9671](https://github.com/paritytech/parity-ethereum/pull/9671))
|
||||
- Eip-712 implementation ([#9631](https://github.com/paritytech/parity-ethereum/pull/9631))
|
||||
- Fix typo ([#9826](https://github.com/paritytech/parity-ethereum/pull/9826))
|
||||
- Clean up serde rename and use rename_all = camelCase when possible ([#9823](https://github.com/paritytech/parity-ethereum/pull/9823))
|
||||
@@ -39,7 +39,7 @@ keccak-hasher = { path = "../util/keccak-hasher" }
|
||||
kvdb = "0.1"
|
||||
kvdb-memorydb = "0.1"
|
||||
kvdb-rocksdb = { version = "0.1.3", optional = true }
|
||||
lazy_static = "1.0"
|
||||
lazy_static = "1.2.0"
|
||||
len-caching-lock = { path = "../util/len-caching-lock" }
|
||||
log = "0.4"
|
||||
lru-cache = "0.1"
|
||||
@@ -50,7 +50,6 @@ num = { version = "0.1", default-features = false, features = ["bigint"] }
|
||||
num_cpus = "1.2"
|
||||
parity-bytes = "0.1"
|
||||
parity-crypto = "0.3.0"
|
||||
parity-machine = { path = "../machine" }
|
||||
parity-snappy = "0.1"
|
||||
parking_lot = "0.7"
|
||||
trie-db = "0.11.0"
|
||||
@@ -64,6 +63,7 @@ serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
stats = { path = "../util/stats" }
|
||||
tempdir = {version="0.3", optional = true}
|
||||
time-utils = { path = "../util/time-utils" }
|
||||
trace-time = "0.1"
|
||||
triehash-ethereum = { version = "0.2", path = "../util/triehash-ethereum" }
|
||||
unexpected = { path = "../util/unexpected" }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -116,6 +116,9 @@ pub trait LightChainClient: Send + Sync {
|
||||
/// Query whether a block is known.
|
||||
fn is_known(&self, hash: &H256) -> bool;
|
||||
|
||||
/// Set the chain via a spec name.
|
||||
fn set_spec_name(&self, new_spec_name: String) -> Result<(), ()>;
|
||||
|
||||
/// Clear the queue.
|
||||
fn clear_queue(&self);
|
||||
|
||||
@@ -164,6 +167,8 @@ pub struct Client<T> {
|
||||
listeners: RwLock<Vec<Weak<LightChainNotify>>>,
|
||||
fetcher: T,
|
||||
verify_full: bool,
|
||||
/// A closure to call when we want to restart the client
|
||||
exit_handler: Mutex<Option<Box<Fn(String) + 'static + Send>>>,
|
||||
}
|
||||
|
||||
impl<T: ChainDataFetcher> Client<T> {
|
||||
@@ -190,6 +195,7 @@ impl<T: ChainDataFetcher> Client<T> {
|
||||
listeners: RwLock::new(vec![]),
|
||||
fetcher,
|
||||
verify_full: config.verify_full,
|
||||
exit_handler: Mutex::new(None),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -360,6 +366,14 @@ impl<T: ChainDataFetcher> Client<T> {
|
||||
self.chain.heap_size_of_children()
|
||||
}
|
||||
|
||||
/// Set a closure to call when the client wants to be restarted.
|
||||
///
|
||||
/// The parameter passed to the callback is the name of the new chain spec to use after
|
||||
/// the restart.
|
||||
pub fn set_exit_handler<F>(&self, f: F) where F: Fn(String) + 'static + Send {
|
||||
*self.exit_handler.lock() = Some(Box::new(f));
|
||||
}
|
||||
|
||||
/// Get a handle to the verification engine.
|
||||
pub fn engine(&self) -> &Arc<EthEngine> {
|
||||
&self.engine
|
||||
@@ -563,6 +577,17 @@ impl<T: ChainDataFetcher> LightChainClient for Client<T> {
|
||||
Client::engine(self)
|
||||
}
|
||||
|
||||
fn set_spec_name(&self, new_spec_name: String) -> Result<(), ()> {
|
||||
trace!(target: "mode", "Client::set_spec_name({:?})", new_spec_name);
|
||||
if let Some(ref h) = *self.exit_handler.lock() {
|
||||
(*h)(new_spec_name);
|
||||
Ok(())
|
||||
} else {
|
||||
warn!("Not hypervised; cannot change chain.");
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
fn is_known(&self, hash: &H256) -> bool {
|
||||
self.status(hash) == BlockStatus::InChain
|
||||
}
|
||||
|
||||
@@ -533,6 +533,9 @@ impl LightProtocol {
|
||||
// the timer approach will skip 1 (possibly 2) in rare occasions.
|
||||
if peer_info.sent_head == announcement.head_hash ||
|
||||
peer_info.status.head_num >= announcement.head_num ||
|
||||
// fix for underflow reported in
|
||||
// https://github.com/paritytech/parity-ethereum/issues/10419
|
||||
now < peer_info.last_update ||
|
||||
now - peer_info.last_update < UPDATE_INTERVAL {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use ethcore::executed::{Executed, ExecutionError};
|
||||
use futures::{Poll, Future, Async};
|
||||
use futures::sync::oneshot::{self, Receiver};
|
||||
use network::PeerId;
|
||||
@@ -41,10 +40,10 @@ use cache::Cache;
|
||||
use request::{self as basic_request, Request as NetworkRequest};
|
||||
use self::request::CheckedRequest;
|
||||
|
||||
pub use ethcore::executed::ExecutionResult;
|
||||
pub use self::request::{Request, Response, HeaderRef, Error as ValidityError};
|
||||
pub use self::request_guard::{RequestGuard, Error as RequestError};
|
||||
pub use self::response_guard::{ResponseGuard, Error as ResponseGuardError, Inner as ResponseGuardInner};
|
||||
|
||||
pub use types::request::ResponseError;
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -54,9 +53,6 @@ pub mod request;
|
||||
mod request_guard;
|
||||
mod response_guard;
|
||||
|
||||
/// The result of execution
|
||||
pub type ExecutionResult = Result<Executed, ExecutionError>;
|
||||
|
||||
/// The initial backoff interval for OnDemand queries
|
||||
pub const DEFAULT_REQUEST_MIN_BACKOFF_DURATION: Duration = Duration::from_secs(10);
|
||||
/// The maximum request interval for OnDemand queries
|
||||
@@ -70,6 +66,10 @@ pub const DEFAULT_NUM_CONSECUTIVE_FAILED_REQUESTS: usize = 1;
|
||||
|
||||
/// OnDemand related errors
|
||||
pub mod error {
|
||||
// Silence: `use of deprecated item 'std::error::Error::cause': replaced by Error::source, which can support downcasting`
|
||||
// https://github.com/paritytech/parity-ethereum/issues/10302
|
||||
#![allow(deprecated)]
|
||||
|
||||
use futures::sync::oneshot::Canceled;
|
||||
|
||||
error_chain! {
|
||||
@@ -94,6 +94,24 @@ pub mod error {
|
||||
}
|
||||
}
|
||||
|
||||
/// Public interface for performing network requests `OnDemand`
|
||||
pub trait OnDemandRequester: Send + Sync {
|
||||
/// Submit a strongly-typed batch of requests.
|
||||
///
|
||||
/// Fails if back-reference are not coherent.
|
||||
fn request<T>(&self, ctx: &BasicContext, requests: T) -> Result<OnResponses<T>, basic_request::NoSuchOutput>
|
||||
where
|
||||
T: request::RequestAdapter;
|
||||
|
||||
/// Submit a vector of requests to be processed together.
|
||||
///
|
||||
/// Fails if back-references are not coherent.
|
||||
/// The returned vector of responses will correspond to the requests exactly.
|
||||
fn request_raw(&self, ctx: &BasicContext, requests: Vec<Request>)
|
||||
-> Result<Receiver<PendingResponse>, basic_request::NoSuchOutput>;
|
||||
}
|
||||
|
||||
|
||||
// relevant peer info.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
struct Peer {
|
||||
@@ -355,6 +373,74 @@ pub struct OnDemand {
|
||||
request_number_of_consecutive_errors: usize
|
||||
}
|
||||
|
||||
impl OnDemandRequester for OnDemand {
|
||||
fn request_raw(&self, ctx: &BasicContext, requests: Vec<Request>)
|
||||
-> Result<Receiver<PendingResponse>, basic_request::NoSuchOutput>
|
||||
{
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
if requests.is_empty() {
|
||||
assert!(sender.send(Ok(Vec::new())).is_ok(), "receiver still in scope; qed");
|
||||
return Ok(receiver);
|
||||
}
|
||||
|
||||
let mut builder = basic_request::Builder::default();
|
||||
|
||||
let responses = Vec::with_capacity(requests.len());
|
||||
|
||||
let mut header_producers = HashMap::new();
|
||||
for (i, request) in requests.into_iter().enumerate() {
|
||||
let request = CheckedRequest::from(request);
|
||||
|
||||
// ensure that all requests needing headers will get them.
|
||||
if let Some((idx, field)) = request.needs_header() {
|
||||
// a request chain with a header back-reference is valid only if it both
|
||||
// points to a request that returns a header and has the same back-reference
|
||||
// for the block hash.
|
||||
match header_producers.get(&idx) {
|
||||
Some(ref f) if &field == *f => {}
|
||||
_ => return Err(basic_request::NoSuchOutput),
|
||||
}
|
||||
}
|
||||
if let CheckedRequest::HeaderByHash(ref req, _) = request {
|
||||
header_producers.insert(i, req.0);
|
||||
}
|
||||
|
||||
builder.push(request)?;
|
||||
}
|
||||
|
||||
let requests = builder.build();
|
||||
let net_requests = requests.clone().map_requests(|req| req.into_net_request());
|
||||
let capabilities = guess_capabilities(requests.requests());
|
||||
|
||||
self.submit_pending(ctx, Pending {
|
||||
requests,
|
||||
net_requests,
|
||||
required_capabilities: capabilities,
|
||||
responses,
|
||||
sender,
|
||||
request_guard: RequestGuard::new(
|
||||
self.request_number_of_consecutive_errors as u32,
|
||||
self.request_backoff_rounds_max,
|
||||
self.request_backoff_start,
|
||||
self.request_backoff_max,
|
||||
),
|
||||
response_guard: ResponseGuard::new(self.response_time_window),
|
||||
});
|
||||
|
||||
Ok(receiver)
|
||||
}
|
||||
|
||||
fn request<T>(&self, ctx: &BasicContext, requests: T) -> Result<OnResponses<T>, basic_request::NoSuchOutput>
|
||||
where T: request::RequestAdapter
|
||||
{
|
||||
self.request_raw(ctx, requests.make_requests()).map(|recv| OnResponses {
|
||||
receiver: recv,
|
||||
_marker: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl OnDemand {
|
||||
|
||||
/// Create a new `OnDemand` service with the given cache.
|
||||
@@ -415,77 +501,6 @@ impl OnDemand {
|
||||
me
|
||||
}
|
||||
|
||||
/// Submit a vector of requests to be processed together.
|
||||
///
|
||||
/// Fails if back-references are not coherent.
|
||||
/// The returned vector of responses will correspond to the requests exactly.
|
||||
pub fn request_raw(&self, ctx: &BasicContext, requests: Vec<Request>)
|
||||
-> Result<Receiver<PendingResponse>, basic_request::NoSuchOutput>
|
||||
{
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
if requests.is_empty() {
|
||||
assert!(sender.send(Ok(Vec::new())).is_ok(), "receiver still in scope; qed");
|
||||
return Ok(receiver);
|
||||
}
|
||||
|
||||
let mut builder = basic_request::Builder::default();
|
||||
|
||||
let responses = Vec::with_capacity(requests.len());
|
||||
|
||||
let mut header_producers = HashMap::new();
|
||||
for (i, request) in requests.into_iter().enumerate() {
|
||||
let request = CheckedRequest::from(request);
|
||||
|
||||
// ensure that all requests needing headers will get them.
|
||||
if let Some((idx, field)) = request.needs_header() {
|
||||
// a request chain with a header back-reference is valid only if it both
|
||||
// points to a request that returns a header and has the same back-reference
|
||||
// for the block hash.
|
||||
match header_producers.get(&idx) {
|
||||
Some(ref f) if &field == *f => {}
|
||||
_ => return Err(basic_request::NoSuchOutput),
|
||||
}
|
||||
}
|
||||
if let CheckedRequest::HeaderByHash(ref req, _) = request {
|
||||
header_producers.insert(i, req.0);
|
||||
}
|
||||
|
||||
builder.push(request)?;
|
||||
}
|
||||
|
||||
let requests = builder.build();
|
||||
let net_requests = requests.clone().map_requests(|req| req.into_net_request());
|
||||
let capabilities = guess_capabilities(requests.requests());
|
||||
|
||||
self.submit_pending(ctx, Pending {
|
||||
requests,
|
||||
net_requests,
|
||||
required_capabilities: capabilities,
|
||||
responses,
|
||||
sender,
|
||||
request_guard: RequestGuard::new(
|
||||
self.request_number_of_consecutive_errors as u32,
|
||||
self.request_backoff_rounds_max,
|
||||
self.request_backoff_start,
|
||||
self.request_backoff_max,
|
||||
),
|
||||
response_guard: ResponseGuard::new(self.response_time_window),
|
||||
});
|
||||
|
||||
Ok(receiver)
|
||||
}
|
||||
|
||||
/// Submit a strongly-typed batch of requests.
|
||||
///
|
||||
/// Fails if back-reference are not coherent.
|
||||
pub fn request<T>(&self, ctx: &BasicContext, requests: T) -> Result<OnResponses<T>, basic_request::NoSuchOutput>
|
||||
where T: request::RequestAdapter
|
||||
{
|
||||
self.request_raw(ctx, requests.make_requests()).map(|recv| OnResponses {
|
||||
receiver: recv,
|
||||
_marker: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
// maybe dispatch pending requests.
|
||||
// sometimes
|
||||
|
||||
@@ -29,7 +29,7 @@ use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::thread;
|
||||
|
||||
use super::{request, OnDemand, Peer, HeaderRef};
|
||||
use super::{request, OnDemand, OnDemandRequester, Peer, HeaderRef};
|
||||
|
||||
// useful contexts to give the service.
|
||||
enum Context {
|
||||
|
||||
@@ -255,4 +255,63 @@ mod tests {
|
||||
hash: Field::BackReference(0, 0),
|
||||
})).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn batch_tx_index_backreference() {
|
||||
let mut builder = Builder::default();
|
||||
builder.push(Request::HeaderProof(IncompleteHeaderProofRequest {
|
||||
num: 100.into(), // header proof puts hash at output 0.
|
||||
})).unwrap();
|
||||
builder.push(Request::TransactionIndex(IncompleteTransactionIndexRequest {
|
||||
hash: Field::BackReference(0, 0),
|
||||
})).unwrap();
|
||||
|
||||
let mut batch = builder.build();
|
||||
batch.requests[1].fill(|_req_idx, _out_idx| Ok(Output::Hash(42.into())));
|
||||
|
||||
assert!(batch.next_complete().is_some());
|
||||
batch.answered += 1;
|
||||
assert!(batch.next_complete().is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn batch_tx_index_backreference_public_api() {
|
||||
let mut builder = Builder::default();
|
||||
builder.push(Request::HeaderProof(IncompleteHeaderProofRequest {
|
||||
num: 100.into(), // header proof puts hash at output 0.
|
||||
})).unwrap();
|
||||
builder.push(Request::TransactionIndex(IncompleteTransactionIndexRequest {
|
||||
hash: Field::BackReference(0, 0),
|
||||
})).unwrap();
|
||||
|
||||
let mut batch = builder.build();
|
||||
|
||||
assert!(batch.next_complete().is_some());
|
||||
let hdr_proof_res = header_proof::Response {
|
||||
proof: vec![],
|
||||
hash: 12.into(),
|
||||
td: 21.into(),
|
||||
};
|
||||
batch.supply_response_unchecked(&hdr_proof_res);
|
||||
|
||||
assert!(batch.next_complete().is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn batch_receipts_backreference() {
|
||||
let mut builder = Builder::default();
|
||||
builder.push(Request::HeaderProof(IncompleteHeaderProofRequest {
|
||||
num: 100.into(), // header proof puts hash at output 0.
|
||||
})).unwrap();
|
||||
builder.push(Request::Receipts(IncompleteReceiptsRequest {
|
||||
hash: Field::BackReference(0, 0),
|
||||
})).unwrap();
|
||||
|
||||
let mut batch = builder.build();
|
||||
batch.requests[1].fill(|_req_idx, _out_idx| Ok(Output::Hash(42.into())));
|
||||
|
||||
assert!(batch.next_complete().is_some());
|
||||
batch.answered += 1;
|
||||
assert!(batch.next_complete().is_some());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -907,7 +907,7 @@ pub mod transaction_index {
|
||||
fn fill<F>(&mut self, oracle: F) where F: Fn(usize, usize) -> Result<Output, NoSuchOutput> {
|
||||
if let Field::BackReference(req, idx) = self.hash {
|
||||
self.hash = match oracle(req, idx) {
|
||||
Ok(Output::Number(hash)) => Field::Scalar(hash.into()),
|
||||
Ok(Output::Hash(hash)) => Field::Scalar(hash.into()),
|
||||
_ => Field::BackReference(req, idx),
|
||||
}
|
||||
}
|
||||
@@ -982,7 +982,7 @@ pub mod block_receipts {
|
||||
fn fill<F>(&mut self, oracle: F) where F: Fn(usize, usize) -> Result<Output, NoSuchOutput> {
|
||||
if let Field::BackReference(req, idx) = self.hash {
|
||||
self.hash = match oracle(req, idx) {
|
||||
Ok(Output::Number(hash)) => Field::Scalar(hash.into()),
|
||||
Ok(Output::Hash(hash)) => Field::Scalar(hash.into()),
|
||||
_ => Field::BackReference(req, idx),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[dependencies]
|
||||
common-types = { path = "../types" }
|
||||
error-chain = { version = "0.12", default-features = false }
|
||||
derive_more = "0.14.0"
|
||||
ethabi = "6.0"
|
||||
ethabi-contract = "6.0"
|
||||
ethabi-derive = "6.0"
|
||||
@@ -36,7 +36,7 @@ serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
tiny-keccak = "1.4"
|
||||
transaction-pool = "1.13.2"
|
||||
transaction-pool = "2.0"
|
||||
url = "1"
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -31,7 +31,7 @@ use crypto;
|
||||
use futures::Future;
|
||||
use fetch::{Fetch, Client as FetchClient, Method, BodyReader, Request};
|
||||
use bytes::{Bytes, ToPretty};
|
||||
use error::{Error, ErrorKind};
|
||||
use error::Error;
|
||||
use url::Url;
|
||||
use super::Signer;
|
||||
use super::key_server_keys::address_to_key;
|
||||
@@ -111,11 +111,11 @@ impl SecretStoreEncryptor {
|
||||
return Ok(key);
|
||||
}
|
||||
let contract_address_signature = self.sign_contract_address(contract_address)?;
|
||||
let requester = self.config.key_server_account.ok_or_else(|| ErrorKind::KeyServerAccountNotSet)?;
|
||||
let requester = self.config.key_server_account.ok_or_else(|| Error::KeyServerAccountNotSet)?;
|
||||
|
||||
// key id in SS is H256 && we have H160 here => expand with assitional zeros
|
||||
let contract_address_extended: H256 = contract_address.into();
|
||||
let base_url = self.config.base_url.clone().ok_or_else(|| ErrorKind::KeyServerNotSet)?;
|
||||
let base_url = self.config.base_url.clone().ok_or_else(|| Error::KeyServerNotSet)?;
|
||||
|
||||
// prepare request url
|
||||
let url = format!("{}/{}/{}{}",
|
||||
@@ -132,16 +132,16 @@ impl SecretStoreEncryptor {
|
||||
Method::GET
|
||||
};
|
||||
|
||||
let url = Url::from_str(&url).map_err(|e| ErrorKind::Encrypt(e.to_string()))?;
|
||||
let url = Url::from_str(&url).map_err(|e| Error::Encrypt(e.to_string()))?;
|
||||
let response = self.client.fetch(Request::new(url, method), Default::default()).wait()
|
||||
.map_err(|e| ErrorKind::Encrypt(e.to_string()))?;
|
||||
.map_err(|e| Error::Encrypt(e.to_string()))?;
|
||||
|
||||
if response.is_not_found() {
|
||||
bail!(ErrorKind::EncryptionKeyNotFound(*contract_address));
|
||||
return Err(Error::EncryptionKeyNotFound(*contract_address));
|
||||
}
|
||||
|
||||
if !response.is_success() {
|
||||
bail!(ErrorKind::Encrypt(response.status().canonical_reason().unwrap_or("unknown").into()));
|
||||
return Err(Error::Encrypt(response.status().canonical_reason().unwrap_or("unknown").into()));
|
||||
}
|
||||
|
||||
// read HTTP response
|
||||
@@ -149,7 +149,7 @@ impl SecretStoreEncryptor {
|
||||
BodyReader::new(response).read_to_string(&mut result)?;
|
||||
|
||||
// response is JSON string (which is, in turn, hex-encoded, encrypted Public)
|
||||
let encrypted_bytes: ethjson::bytes::Bytes = result.trim_matches('\"').parse().map_err(|e| ErrorKind::Encrypt(e))?;
|
||||
let encrypted_bytes: ethjson::bytes::Bytes = result.trim_matches('\"').parse().map_err(|e| Error::Encrypt(e))?;
|
||||
|
||||
// decrypt Public
|
||||
let decrypted_bytes = self.signer.decrypt(requester, &crypto::DEFAULT_MAC, &encrypted_bytes)?;
|
||||
@@ -189,7 +189,7 @@ impl SecretStoreEncryptor {
|
||||
}
|
||||
|
||||
fn sign_contract_address(&self, contract_address: &Address) -> Result<Signature, Error> {
|
||||
let key_server_account = self.config.key_server_account.ok_or_else(|| ErrorKind::KeyServerAccountNotSet)?;
|
||||
let key_server_account = self.config.key_server_account.ok_or_else(|| Error::KeyServerAccountNotSet)?;
|
||||
Ok(self.signer.sign(key_server_account, address_to_key(contract_address))?)
|
||||
}
|
||||
}
|
||||
@@ -204,7 +204,7 @@ impl Encryptor for SecretStoreEncryptor {
|
||||
// retrieve the key, try to generate it if it doesn't exist yet
|
||||
let key = match self.retrieve_key("", false, contract_address) {
|
||||
Ok(key) => Ok(key),
|
||||
Err(Error(ErrorKind::EncryptionKeyNotFound(_), _)) => {
|
||||
Err(Error::EncryptionKeyNotFound(_)) => {
|
||||
trace!(target: "privatetx", "Key for account wasnt found in sstore. Creating. Address: {:?}", contract_address);
|
||||
self.retrieve_key(&format!("/{}", self.config.threshold), true, contract_address)
|
||||
}
|
||||
@@ -215,7 +215,7 @@ impl Encryptor for SecretStoreEncryptor {
|
||||
let mut cypher = Vec::with_capacity(plain_data.len() + initialisation_vector.len());
|
||||
cypher.extend(repeat(0).take(plain_data.len()));
|
||||
crypto::aes::encrypt_128_ctr(&key, initialisation_vector, plain_data, &mut cypher)
|
||||
.map_err(|e| ErrorKind::Encrypt(e.to_string()))?;
|
||||
.map_err(|e| Error::Encrypt(e.to_string()))?;
|
||||
cypher.extend_from_slice(&initialisation_vector);
|
||||
|
||||
Ok(cypher)
|
||||
@@ -230,7 +230,7 @@ impl Encryptor for SecretStoreEncryptor {
|
||||
// initialization vector takes INIT_VEC_LEN bytes
|
||||
let cypher_len = cypher.len();
|
||||
if cypher_len < INIT_VEC_LEN {
|
||||
bail!(ErrorKind::Decrypt("Invalid cypher".into()));
|
||||
return Err(Error::Decrypt("Invalid cypher".into()));
|
||||
}
|
||||
|
||||
// retrieve existing key
|
||||
@@ -241,7 +241,7 @@ impl Encryptor for SecretStoreEncryptor {
|
||||
let mut plain_data = Vec::with_capacity(cypher_len - INIT_VEC_LEN);
|
||||
plain_data.extend(repeat(0).take(cypher_len - INIT_VEC_LEN));
|
||||
crypto::aes::decrypt_128_ctr(&key, &iv, cypher, &mut plain_data)
|
||||
.map_err(|e| ErrorKind::Decrypt(e.to_string()))?;
|
||||
.map_err(|e| Error::Decrypt(e.to_string()))?;
|
||||
Ok(plain_data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::error;
|
||||
use derive_more::Display;
|
||||
use ethereum_types::Address;
|
||||
use rlp::DecoderError;
|
||||
use ethtrie::TrieError;
|
||||
@@ -21,173 +23,173 @@ use ethcore::error::{Error as EthcoreError, ExecutionError};
|
||||
use types::transaction::Error as TransactionError;
|
||||
use ethkey::Error as KeyError;
|
||||
use ethkey::crypto::Error as CryptoError;
|
||||
use txpool::Error as TxPoolError;
|
||||
use txpool::VerifiedTransaction;
|
||||
use private_transactions::VerifiedPrivateTransaction;
|
||||
|
||||
error_chain! {
|
||||
foreign_links {
|
||||
Io(::std::io::Error) #[doc = "Error concerning the Rust standard library's IO subsystem."];
|
||||
Decoder(DecoderError) #[doc = "RLP decoding error."];
|
||||
Trie(TrieError) #[doc = "Error concerning TrieDBs."];
|
||||
Txpool(TxPoolError) #[doc = "Tx pool error."];
|
||||
Crypto(CryptoError) #[doc = "Crypto error."];
|
||||
type TxPoolError = txpool::Error<<VerifiedPrivateTransaction as VerifiedTransaction>::Hash>;
|
||||
|
||||
#[derive(Debug, Display)]
|
||||
pub enum Error {
|
||||
/// Error concerning the Rust standard library's IO subsystem.
|
||||
#[display(fmt = "Io Error: {}", _0)]
|
||||
Io(::std::io::Error),
|
||||
/// RLP decoding error.
|
||||
#[display(fmt = "Decoder Error: {}", _0)]
|
||||
Decoder(DecoderError),
|
||||
/// Error concerning TrieDBs.
|
||||
#[display(fmt = "Trie Error: {}", _0)]
|
||||
Trie(TrieError),
|
||||
/// Transaction pool error.
|
||||
#[display(fmt = "Transaction Pool Error: {}", _0)]
|
||||
TxPool(TxPoolError),
|
||||
/// Crypto error.
|
||||
#[display(fmt = "Crypto Error {}", _0)]
|
||||
Crypto(CryptoError),
|
||||
/// Encryption error.
|
||||
#[display(fmt = "Encryption error. ({})", _0)]
|
||||
Encrypt(String),
|
||||
/// Decryption error.
|
||||
#[display(fmt = "Decryption error. ({})", _0)]
|
||||
Decrypt(String),
|
||||
/// Address not authorized.
|
||||
#[display(fmt = "Private transaction execution is not authorised for {}", _0)]
|
||||
NotAuthorised(Address),
|
||||
/// Transaction creates more than one contract.
|
||||
#[display(fmt = "Private transaction created too many contracts")]
|
||||
TooManyContracts,
|
||||
/// Contract call error.
|
||||
#[display(fmt = "Contract call error. ({})", _0)]
|
||||
Call(String),
|
||||
/// State is not available.
|
||||
#[display(fmt = "State is not available")]
|
||||
StatePruned,
|
||||
/// State is incorrect.
|
||||
#[display(fmt = "State is incorrect")]
|
||||
StateIncorrect,
|
||||
/// Wrong private transaction type.
|
||||
#[display(fmt = "Wrong private transaction type")]
|
||||
BadTransactionType,
|
||||
/// Contract does not exist or was not created.
|
||||
#[display(fmt = "Contract does not exist or was not created")]
|
||||
ContractDoesNotExist,
|
||||
/// Reference to the client is corrupted.
|
||||
#[display(fmt = "Reference to the client is corrupted")]
|
||||
ClientIsMalformed,
|
||||
/// Queue of private transactions for verification is full.
|
||||
#[display(fmt = "Queue of private transactions for verification is full")]
|
||||
QueueIsFull,
|
||||
/// The transaction already exists in queue of private transactions.
|
||||
#[display(fmt = "The transaction already exists in queue of private transactions.")]
|
||||
PrivateTransactionAlreadyImported,
|
||||
/// The information about private transaction is not found in the store.
|
||||
#[display(fmt = "The information about private transaction is not found in the store.")]
|
||||
PrivateTransactionNotFound,
|
||||
/// Account for signing public transactions not set.
|
||||
#[display(fmt = "Account for signing public transactions not set.")]
|
||||
SignerAccountNotSet,
|
||||
/// Account for validating private transactions not set.
|
||||
#[display(fmt = "Account for validating private transactions not set.")]
|
||||
ValidatorAccountNotSet,
|
||||
/// Account for signing requests to key server not set.
|
||||
#[display(fmt = "Account for signing requests to key server not set.")]
|
||||
KeyServerAccountNotSet,
|
||||
/// Encryption key is not found on key server.
|
||||
#[display(fmt = "Encryption key is not found on key server for {}", _0)]
|
||||
EncryptionKeyNotFound(Address),
|
||||
/// Key server URL is not set.
|
||||
#[display(fmt = "Key server URL is not set.")]
|
||||
KeyServerNotSet,
|
||||
/// VM execution error.
|
||||
#[display(fmt = "VM execution error {}", _0)]
|
||||
Execution(ExecutionError),
|
||||
/// General signing error.
|
||||
#[display(fmt = "General signing error {}", _0)]
|
||||
Key(KeyError),
|
||||
/// Error of transactions processing.
|
||||
#[display(fmt = "Error of transactions processing {}", _0)]
|
||||
Transaction(TransactionError),
|
||||
/// General ethcore error.
|
||||
#[display(fmt = "General ethcore error {}", _0)]
|
||||
Ethcore(EthcoreError),
|
||||
/// A convenient variant for String.
|
||||
#[display(fmt = "{}", _0)]
|
||||
Msg(String),
|
||||
}
|
||||
|
||||
impl error::Error for Error {
|
||||
fn source(&self) -> Option<&(error::Error + 'static)> {
|
||||
match self {
|
||||
Error::Io(e) => Some(e),
|
||||
Error::Decoder(e) => Some(e),
|
||||
Error::Trie(e) => Some(e),
|
||||
Error::TxPool(e) => Some(e),
|
||||
Error::Crypto(e) => Some(e),
|
||||
Error::Execution(e) => Some(e),
|
||||
Error::Key(e) => Some(e),
|
||||
Error::Transaction(e) => Some(e),
|
||||
Error::Ethcore(e) => Some(e),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
errors {
|
||||
#[doc = "Encryption error."]
|
||||
Encrypt(err: String) {
|
||||
description("Encryption error"),
|
||||
display("Encryption error. ({})", err),
|
||||
}
|
||||
impl From<String> for Error {
|
||||
fn from(s: String) -> Self {
|
||||
Error::Msg(s)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = "Decryption error."]
|
||||
Decrypt(err: String) {
|
||||
description("Decryption error"),
|
||||
display("Decryption error. ({})", err),
|
||||
}
|
||||
|
||||
#[doc = "Address not authorized."]
|
||||
NotAuthorised(address: Address) {
|
||||
description("Address not authorized"),
|
||||
display("Private transaction execution is not authorised for {}", address),
|
||||
}
|
||||
|
||||
#[doc = "Transaction creates more than one contract."]
|
||||
TooManyContracts {
|
||||
description("Transaction creates more than one contract."),
|
||||
display("Private transaction created too many contracts"),
|
||||
}
|
||||
|
||||
#[doc = "Contract call error."]
|
||||
Call(err: String) {
|
||||
description("Contract call error."),
|
||||
display("Contract call error. ({})", err),
|
||||
}
|
||||
|
||||
#[doc = "State is not available."]
|
||||
StatePruned {
|
||||
description("State is not available."),
|
||||
display("State is not available"),
|
||||
}
|
||||
|
||||
#[doc = "State is incorrect."]
|
||||
StateIncorrect {
|
||||
description("State is incorrect."),
|
||||
display("State is incorrect"),
|
||||
}
|
||||
|
||||
#[doc = "Wrong private transaction type."]
|
||||
BadTransactionType {
|
||||
description("Wrong private transaction type."),
|
||||
display("Wrong private transaction type"),
|
||||
}
|
||||
|
||||
#[doc = "Contract does not exist or was not created."]
|
||||
ContractDoesNotExist {
|
||||
description("Contract does not exist or was not created."),
|
||||
display("Contract does not exist or was not created"),
|
||||
}
|
||||
|
||||
#[doc = "Reference to the client is corrupted."]
|
||||
ClientIsMalformed {
|
||||
description("Reference to the client is corrupted."),
|
||||
display("Reference to the client is corrupted"),
|
||||
}
|
||||
|
||||
#[doc = "Queue of private transactions for verification is full."]
|
||||
QueueIsFull {
|
||||
description("Queue of private transactions for verification is full."),
|
||||
display("Queue of private transactions for verification is full"),
|
||||
}
|
||||
|
||||
#[doc = "The transaction already exists in queue of private transactions."]
|
||||
PrivateTransactionAlreadyImported {
|
||||
description("The transaction already exists in queue of private transactions."),
|
||||
display("The transaction already exists in queue of private transactions."),
|
||||
}
|
||||
|
||||
#[doc = "The information about private transaction is not found in the store."]
|
||||
PrivateTransactionNotFound {
|
||||
description("The information about private transaction is not found in the store."),
|
||||
display("The information about private transaction is not found in the store."),
|
||||
}
|
||||
|
||||
#[doc = "Account for signing public transactions not set."]
|
||||
SignerAccountNotSet {
|
||||
description("Account for signing public transactions not set."),
|
||||
display("Account for signing public transactions not set."),
|
||||
}
|
||||
|
||||
#[doc = "Account for validating private transactions not set."]
|
||||
ValidatorAccountNotSet {
|
||||
description("Account for validating private transactions not set."),
|
||||
display("Account for validating private transactions not set."),
|
||||
}
|
||||
|
||||
#[doc = "Account for signing requests to key server not set."]
|
||||
KeyServerAccountNotSet {
|
||||
description("Account for signing requests to key server not set."),
|
||||
display("Account for signing requests to key server not set."),
|
||||
}
|
||||
|
||||
#[doc = "Encryption key is not found on key server."]
|
||||
EncryptionKeyNotFound(address: Address) {
|
||||
description("Encryption key is not found on key server"),
|
||||
display("Encryption key is not found on key server for {}", address),
|
||||
}
|
||||
|
||||
#[doc = "Key server URL is not set."]
|
||||
KeyServerNotSet {
|
||||
description("Key server URL is not set."),
|
||||
display("Key server URL is not set."),
|
||||
}
|
||||
|
||||
#[doc = "VM execution error."]
|
||||
Execution(err: ExecutionError) {
|
||||
description("VM execution error."),
|
||||
display("VM execution error {}", err),
|
||||
}
|
||||
|
||||
#[doc = "General signing error."]
|
||||
Key(err: KeyError) {
|
||||
description("General signing error."),
|
||||
display("General signing error {}", err),
|
||||
}
|
||||
|
||||
#[doc = "Error of transactions processing."]
|
||||
Transaction(err: TransactionError) {
|
||||
description("Error of transactions processing."),
|
||||
display("Error of transactions processing {}", err),
|
||||
}
|
||||
|
||||
#[doc = "General ethcore error."]
|
||||
Ethcore(err: EthcoreError) {
|
||||
description("General ethcore error."),
|
||||
display("General ethcore error {}", err),
|
||||
}
|
||||
impl From<std::io::Error> for Error {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
Error::Io(err).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KeyError> for Error {
|
||||
fn from(err: KeyError) -> Self {
|
||||
ErrorKind::Key(err).into()
|
||||
Error::Key(err).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CryptoError> for Error {
|
||||
fn from(err: CryptoError) -> Self {
|
||||
Error::Crypto(err).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DecoderError> for Error {
|
||||
fn from(err: DecoderError) -> Self {
|
||||
Error::Decoder(err).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExecutionError> for Error {
|
||||
fn from(err: ExecutionError) -> Self {
|
||||
ErrorKind::Execution(err).into()
|
||||
Error::Execution(err).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TransactionError> for Error {
|
||||
fn from(err: TransactionError) -> Self {
|
||||
ErrorKind::Transaction(err).into()
|
||||
Error::Transaction(err).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TrieError> for Error {
|
||||
fn from(err: TrieError) -> Self {
|
||||
Error::Trie(err).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TxPoolError> for Error {
|
||||
fn from(err: TxPoolError) -> Self {
|
||||
Error::TxPool(err).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EthcoreError> for Error {
|
||||
fn from(err: EthcoreError) -> Self {
|
||||
ErrorKind::Ethcore(err).into()
|
||||
Error::Ethcore(err).into()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,8 +54,7 @@ extern crate log;
|
||||
extern crate ethabi_derive;
|
||||
#[macro_use]
|
||||
extern crate ethabi_contract;
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
extern crate derive_more;
|
||||
#[macro_use]
|
||||
extern crate rlp_derive;
|
||||
|
||||
@@ -68,7 +67,7 @@ pub use encryptor::{Encryptor, SecretStoreEncryptor, EncryptorConfig, NoopEncryp
|
||||
pub use key_server_keys::{KeyProvider, SecretStoreKeys, StoringKeyProvider};
|
||||
pub use private_transactions::{VerifiedPrivateTransaction, VerificationStore, PrivateTransactionSigningDesc, SigningStore};
|
||||
pub use messages::{PrivateTransaction, SignedPrivateTransaction};
|
||||
pub use error::{Error, ErrorKind};
|
||||
pub use error::Error;
|
||||
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::collections::{HashMap, HashSet, BTreeMap};
|
||||
@@ -238,10 +237,10 @@ impl Provider {
|
||||
trace!(target: "privatetx", "Creating private transaction from regular transaction: {:?}", signed_transaction);
|
||||
if self.signer_account.is_none() {
|
||||
warn!(target: "privatetx", "Signing account not set");
|
||||
bail!(ErrorKind::SignerAccountNotSet);
|
||||
return Err(Error::SignerAccountNotSet);
|
||||
}
|
||||
let tx_hash = signed_transaction.hash();
|
||||
let contract = Self::contract_address_from_transaction(&signed_transaction).map_err(|_| ErrorKind::BadTransactionType)?;
|
||||
let contract = Self::contract_address_from_transaction(&signed_transaction).map_err(|_| Error::BadTransactionType)?;
|
||||
let data = signed_transaction.rlp_bytes();
|
||||
let encrypted_transaction = self.encrypt(&contract, &Self::iv_from_transaction(&signed_transaction), &data)?;
|
||||
let private = PrivateTransaction::new(encrypted_transaction, contract);
|
||||
@@ -278,13 +277,12 @@ impl Provider {
|
||||
|
||||
fn pool_client<'a>(&'a self, nonce_cache: &'a NonceCache, local_accounts: &'a HashSet<Address>) -> miner::pool_client::PoolClient<'a, Client> {
|
||||
let engine = self.client.engine();
|
||||
let refuse_service_transactions = true;
|
||||
miner::pool_client::PoolClient::new(
|
||||
&*self.client,
|
||||
nonce_cache,
|
||||
engine,
|
||||
local_accounts,
|
||||
refuse_service_transactions,
|
||||
None, // refuse_service_transactions = true
|
||||
)
|
||||
}
|
||||
|
||||
@@ -309,19 +307,19 @@ impl Provider {
|
||||
// TODO #9825 [ToDr] Usage of BlockId::Latest
|
||||
let contract_nonce = self.get_contract_nonce(&contract, BlockId::Latest);
|
||||
if let Err(e) = contract_nonce {
|
||||
bail!("Cannot retrieve contract nonce: {:?}", e);
|
||||
return Err(format!("Cannot retrieve contract nonce: {:?}", e).into());
|
||||
}
|
||||
let contract_nonce = contract_nonce.expect("Error was checked before");
|
||||
let private_state = self.execute_private_transaction(BlockId::Latest, &transaction.transaction);
|
||||
if let Err(e) = private_state {
|
||||
bail!("Cannot retrieve private state: {:?}", e);
|
||||
return Err(format!("Cannot retrieve private state: {:?}", e).into());
|
||||
}
|
||||
let private_state = private_state.expect("Error was checked before");
|
||||
let private_state_hash = self.calculate_state_hash(&private_state, contract_nonce);
|
||||
trace!(target: "privatetx", "Hashed effective private state for validator: {:?}", private_state_hash);
|
||||
let signed_state = self.accounts.sign(validator_account, private_state_hash);
|
||||
if let Err(e) = signed_state {
|
||||
bail!("Cannot sign the state: {:?}", e);
|
||||
return Err(format!("Cannot sign the state: {:?}", e).into());
|
||||
}
|
||||
let signed_state = signed_state.expect("Error was checked before");
|
||||
let signed_private_transaction = SignedPrivateTransaction::new(private_hash, signed_state, None);
|
||||
@@ -362,25 +360,27 @@ impl Provider {
|
||||
signatures.push(signed_tx.signature());
|
||||
let rsv: Vec<Signature> = signatures.into_iter().map(|sign| sign.into_electrum().into()).collect();
|
||||
// Create public transaction
|
||||
let signer_account = self.signer_account.ok_or_else(|| Error::SignerAccountNotSet)?;
|
||||
let state = self.client.state_at(BlockId::Latest).ok_or(Error::StatePruned)?;
|
||||
let nonce = state.nonce(&signer_account)?;
|
||||
let public_tx = self.public_transaction(
|
||||
desc.state.clone(),
|
||||
&desc.original_transaction,
|
||||
&rsv,
|
||||
desc.original_transaction.nonce,
|
||||
nonce,
|
||||
desc.original_transaction.gas_price
|
||||
)?;
|
||||
trace!(target: "privatetx", "Last required signature received, public transaction created: {:?}", public_tx);
|
||||
// Sign and add it to the queue
|
||||
let chain_id = desc.original_transaction.chain_id();
|
||||
let hash = public_tx.hash(chain_id);
|
||||
let signer_account = self.signer_account.ok_or_else(|| ErrorKind::SignerAccountNotSet)?;
|
||||
let signature = self.accounts.sign(signer_account, hash)?;
|
||||
let signed = SignedTransaction::new(public_tx.with_signature(signature, chain_id))?;
|
||||
match self.miner.import_own_transaction(&*self.client, signed.into()) {
|
||||
Ok(_) => trace!(target: "privatetx", "Public transaction added to queue"),
|
||||
Err(err) => {
|
||||
warn!(target: "privatetx", "Failed to add transaction to queue, error: {:?}", err);
|
||||
bail!(err);
|
||||
return Err(err.into());
|
||||
}
|
||||
}
|
||||
// Notify about state changes
|
||||
@@ -395,7 +395,7 @@ impl Provider {
|
||||
// Remove from store for signing
|
||||
if let Err(err) = self.transactions_for_signing.write().remove(&private_hash) {
|
||||
warn!(target: "privatetx", "Failed to remove transaction from signing store, error: {:?}", err);
|
||||
bail!(err);
|
||||
return Err(err);
|
||||
}
|
||||
} else {
|
||||
// Add signature to the store
|
||||
@@ -403,7 +403,7 @@ impl Provider {
|
||||
Ok(_) => trace!(target: "privatetx", "Signature stored for private transaction"),
|
||||
Err(err) => {
|
||||
warn!(target: "privatetx", "Failed to add signature to signing store, error: {:?}", err);
|
||||
bail!(err);
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -415,7 +415,7 @@ impl Provider {
|
||||
Action::Call(contract) => Ok(contract),
|
||||
_ => {
|
||||
warn!(target: "privatetx", "Incorrect type of action for the transaction");
|
||||
bail!(ErrorKind::BadTransactionType);
|
||||
return Err(Error::BadTransactionType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -434,13 +434,13 @@ impl Provider {
|
||||
}
|
||||
false => {
|
||||
warn!(target: "privatetx", "Sender's state doesn't correspond to validator's");
|
||||
bail!(ErrorKind::StateIncorrect);
|
||||
return Err(Error::StateIncorrect);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(target: "privatetx", "Sender's state doesn't correspond to validator's, error {:?}", err);
|
||||
bail!(err);
|
||||
return Err(err.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -480,21 +480,21 @@ impl Provider {
|
||||
fn get_decrypted_state(&self, address: &Address, block: BlockId) -> Result<Bytes, Error> {
|
||||
let (data, decoder) = private_contract::functions::state::call();
|
||||
let value = self.client.call_contract(block, *address, data)?;
|
||||
let state = decoder.decode(&value).map_err(|e| ErrorKind::Call(format!("Contract call failed {:?}", e)))?;
|
||||
let state = decoder.decode(&value).map_err(|e| Error::Call(format!("Contract call failed {:?}", e)))?;
|
||||
self.decrypt(address, &state)
|
||||
}
|
||||
|
||||
fn get_decrypted_code(&self, address: &Address, block: BlockId) -> Result<Bytes, Error> {
|
||||
let (data, decoder) = private_contract::functions::code::call();
|
||||
let value = self.client.call_contract(block, *address, data)?;
|
||||
let state = decoder.decode(&value).map_err(|e| ErrorKind::Call(format!("Contract call failed {:?}", e)))?;
|
||||
let state = decoder.decode(&value).map_err(|e| Error::Call(format!("Contract call failed {:?}", e)))?;
|
||||
self.decrypt(address, &state)
|
||||
}
|
||||
|
||||
pub fn get_contract_nonce(&self, address: &Address, block: BlockId) -> Result<U256, Error> {
|
||||
let (data, decoder) = private_contract::functions::nonce::call();
|
||||
let value = self.client.call_contract(block, *address, data)?;
|
||||
decoder.decode(&value).map_err(|e| ErrorKind::Call(format!("Contract call failed {:?}", e)).into())
|
||||
decoder.decode(&value).map_err(|e| Error::Call(format!("Contract call failed {:?}", e)).into())
|
||||
}
|
||||
|
||||
fn snapshot_to_storage(raw: Bytes) -> HashMap<H256, H256> {
|
||||
@@ -531,10 +531,10 @@ impl Provider {
|
||||
T: Tracer,
|
||||
V: VMTracer,
|
||||
{
|
||||
let mut env_info = self.client.env_info(block).ok_or(ErrorKind::StatePruned)?;
|
||||
let mut env_info = self.client.env_info(block).ok_or(Error::StatePruned)?;
|
||||
env_info.gas_limit = transaction.gas;
|
||||
|
||||
let mut state = self.client.state_at(block).ok_or(ErrorKind::StatePruned)?;
|
||||
let mut state = self.client.state_at(block).ok_or(Error::StatePruned)?;
|
||||
// TODO #9825 in case of BlockId::Latest these need to operate on the same state
|
||||
let contract_address = match transaction.action {
|
||||
Action::Call(ref contract_address) => {
|
||||
@@ -610,15 +610,15 @@ impl Provider {
|
||||
/// Create encrypted public contract deployment transaction.
|
||||
pub fn public_creation_transaction(&self, block: BlockId, source: &SignedTransaction, validators: &[Address], gas_price: U256) -> Result<(Transaction, Address), Error> {
|
||||
if let Action::Call(_) = source.action {
|
||||
bail!(ErrorKind::BadTransactionType);
|
||||
return Err(Error::BadTransactionType);
|
||||
}
|
||||
let sender = source.sender();
|
||||
let state = self.client.state_at(block).ok_or(ErrorKind::StatePruned)?;
|
||||
let state = self.client.state_at(block).ok_or(Error::StatePruned)?;
|
||||
let nonce = state.nonce(&sender)?;
|
||||
let executed = self.execute_private(source, TransactOptions::with_no_tracing(), block)?;
|
||||
let header = self.client.block_header(block)
|
||||
.ok_or(ErrorKind::StatePruned)
|
||||
.and_then(|h| h.decode().map_err(|_| ErrorKind::StateIncorrect).into())?;
|
||||
.ok_or(Error::StatePruned)
|
||||
.and_then(|h| h.decode().map_err(|_| Error::StateIncorrect).into())?;
|
||||
let (executed_code, executed_state) = (executed.code.unwrap_or_default(), executed.state);
|
||||
let tx_data = Self::generate_constructor(validators, executed_code.clone(), executed_state.clone());
|
||||
let mut tx = Transaction {
|
||||
@@ -649,7 +649,7 @@ impl Provider {
|
||||
/// Create encrypted public contract deployment transaction. Returns updated encrypted state.
|
||||
pub fn execute_private_transaction(&self, block: BlockId, source: &SignedTransaction) -> Result<Bytes, Error> {
|
||||
if let Action::Create = source.action {
|
||||
bail!(ErrorKind::BadTransactionType);
|
||||
return Err(Error::BadTransactionType);
|
||||
}
|
||||
let result = self.execute_private(source, TransactOptions::with_no_tracing(), block)?;
|
||||
Ok(result.state)
|
||||
@@ -678,7 +678,7 @@ impl Provider {
|
||||
pub fn get_validators(&self, block: BlockId, address: &Address) -> Result<Vec<Address>, Error> {
|
||||
let (data, decoder) = private_contract::functions::get_validators::call();
|
||||
let value = self.client.call_contract(block, *address, data)?;
|
||||
decoder.decode(&value).map_err(|e| ErrorKind::Call(format!("Contract call failed {:?}", e)).into())
|
||||
decoder.decode(&value).map_err(|e| Error::Call(format!("Contract call failed {:?}", e)).into())
|
||||
}
|
||||
|
||||
fn get_contract_version(&self, block: BlockId, address: &Address) -> usize {
|
||||
|
||||
@@ -28,7 +28,7 @@ use parking_lot::RwLock;
|
||||
use types::transaction::{UnverifiedTransaction, SignedTransaction};
|
||||
use txpool;
|
||||
use txpool::{VerifiedTransaction, Verifier};
|
||||
use error::{Error, ErrorKind};
|
||||
use error::Error;
|
||||
|
||||
type Pool = txpool::Pool<VerifiedPrivateTransaction, pool::scoring::NonceAndGasPrice>;
|
||||
|
||||
@@ -154,7 +154,7 @@ impl Default for VerificationStore {
|
||||
|
||||
impl VerificationStore {
|
||||
/// Adds private transaction for verification into the store
|
||||
pub fn add_transaction<C: pool::client::Client>(
|
||||
pub fn add_transaction<C: pool::client::Client + pool::client::NonceClient + Clone>(
|
||||
&self,
|
||||
transaction: UnverifiedTransaction,
|
||||
validator_account: Option<Address>,
|
||||
@@ -164,7 +164,7 @@ impl VerificationStore {
|
||||
|
||||
let options = self.verification_options.clone();
|
||||
// Use pool's verifying pipeline for original transaction's verification
|
||||
let verifier = pool::verifier::Verifier::new(client, options, Default::default(), None);
|
||||
let verifier = pool::verifier::Verifier::new(client.clone(), options, Default::default(), None);
|
||||
let unverified = pool::verifier::Transaction::Unverified(transaction);
|
||||
let verified_tx = verifier.verify_transaction(unverified)?;
|
||||
let signed_tx: SignedTransaction = verified_tx.signed().clone();
|
||||
@@ -177,8 +177,9 @@ impl VerificationStore {
|
||||
transaction_hash: signed_hash,
|
||||
transaction_sender: signed_sender,
|
||||
};
|
||||
let mut pool = self.verification_pool.write();
|
||||
pool.import(verified)?;
|
||||
let replace = pool::replace::ReplaceByScoreAndReadiness::new(
|
||||
self.verification_pool.read().scoring().clone(), client);
|
||||
self.verification_pool.write().import(verified, &replace)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -228,7 +229,7 @@ impl SigningStore {
|
||||
contract_nonce: U256,
|
||||
) -> Result<(), Error> {
|
||||
if self.transactions.len() > MAX_QUEUE_LEN {
|
||||
bail!(ErrorKind::QueueIsFull);
|
||||
return Err(Error::QueueIsFull);
|
||||
}
|
||||
|
||||
self.transactions.insert(private_hash, PrivateTransactionSigningDesc {
|
||||
@@ -254,7 +255,7 @@ impl SigningStore {
|
||||
|
||||
/// Adds received signature for the stored private transaction
|
||||
pub fn add_signature(&mut self, private_hash: &H256, signature: Signature) -> Result<(), Error> {
|
||||
let desc = self.transactions.get_mut(private_hash).ok_or_else(|| ErrorKind::PrivateTransactionNotFound)?;
|
||||
let desc = self.transactions.get_mut(private_hash).ok_or_else(|| Error::PrivateTransactionNotFound)?;
|
||||
if !desc.received_signatures.contains(&signature) {
|
||||
desc.received_signatures.push(signature);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,87 +0,0 @@
|
||||
{
|
||||
"name": "Easthub",
|
||||
"dataDir": "easthub",
|
||||
"engine": {
|
||||
"Ethash": {
|
||||
"params": {
|
||||
"minimumDifficulty": "0x020000",
|
||||
"difficultyBoundDivisor": "0x0800",
|
||||
"durationLimit": "0x0d",
|
||||
"blockReward": "0x2B5E3AF16B1880000",
|
||||
"homesteadTransition": "0x0",
|
||||
"bombDefuseTransition": "0x0",
|
||||
"ecip1017EraRounds": 5000000
|
||||
}
|
||||
}
|
||||
},
|
||||
"params": {
|
||||
"gasLimitBoundDivisor": "0x0400",
|
||||
"registrar": "0x0000000000000000000000000000000000000000",
|
||||
"accountStartNonce": "0x00",
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID": "0x7",
|
||||
"chainID": "0x7",
|
||||
"eip150Transition": "0x0",
|
||||
"eip160Transition": "0x0",
|
||||
"eip155Transition": "0x0",
|
||||
"eip161abcTransition": "0x7fffffffffffffff",
|
||||
"eip161dTransition": "0x7fffffffffffffff"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
"ethereum": {
|
||||
"nonce": "0x0000000000000042",
|
||||
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
},
|
||||
"difficulty": "0x0400000000",
|
||||
"author": "0x0000000000000000000000000000000000000000",
|
||||
"timestamp": "0x00",
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"extraData": "0x323031382045617374636f696e2050726f6a656374",
|
||||
"gasLimit": "0x1388"
|
||||
},
|
||||
"nodes": [
|
||||
"enode://ca57e40edb95a08a81b85a91e91099a0aaab777ad329ea7f3f772bc0fd511a276a5d84944725d181ff80f8c7dc1034814bff25b9723b03363d48617fed4b15f0@13.125.109.174:30303",
|
||||
"enode://57254e23a7e5fe1e081ee5d1b236e37735a120660daeb4bf1fec6943a82c915c5b6fad23eeb1a43a27c23f236e084e8051aaa28f7d4139149f844747facb62bb@18.217.39.51:30303",
|
||||
"enode://ef248f327c73c0318f4d51a62270b0612f3c4a4fd04b77d04854dc355980e137708d1e48811bc91387b0d7eb85cf447d8bbc095404f39bb7064e76751bda9cd4@52.221.160.236:30303",
|
||||
"enode://bf6f0e37dd733cf04f2b079c753d2dea7cc7c59d8637eff9a8e63e17d08e2bfc91229fbb2dff08fe6ee12e51c1b6f8ed969d7042b89d77029e7ea02b05e17be3@18.197.47.177: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 } } } },
|
||||
"20c1252a8cb33a7a9a257b2a4cfeed8daf87c847": {
|
||||
"balance": "100000000000000000000000000"
|
||||
},
|
||||
"9dcd37c8e5aea3a0d37c5d0a2db683362d81febd": {
|
||||
"balance": "100000000000000000000000000"
|
||||
},
|
||||
"9eff080302333f44a60bfd8c33bd63015c6d921b": {
|
||||
"balance": "100000000000000000000000000"
|
||||
},
|
||||
"c1df2e5de98d5c41fec0642dc302971f5d3500bd": {
|
||||
"balance": "100000000000000000000000000"
|
||||
},
|
||||
"2e0fb67cd1d029cbaea4b74c361efcc06b3105fd": {
|
||||
"balance": "100000000000000000000000000"
|
||||
},
|
||||
"2b6425cc3cd90654f077889ef7262ac2f5846460": {
|
||||
"balance": "100000000000000000000000000"
|
||||
},
|
||||
"28562041230c6d575e233e4ed1b35c514884d964": {
|
||||
"balance": "100000000000000000000000000"
|
||||
},
|
||||
"16eb6896a5a83d39ac762d79d21f825f5f980d12": {
|
||||
"balance": "100000000000000000000000000"
|
||||
},
|
||||
"f09e3f1de27dd03a1ac0a021b2d9e45bde1b360c": {
|
||||
"balance": "100000000000000000000000000"
|
||||
},
|
||||
"2d87547819c6433f208ee3096161cdb2835a2333": {
|
||||
"balance": "100000000000000000000000000"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -181,8 +181,8 @@
|
||||
"stateRoot": "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544"
|
||||
},
|
||||
"hardcodedSync": {
|
||||
"header": "f9020aa016c0aa39e09bf4ec53d630cdea0be984445c6c76f769b1541ce6b11c281c2fbda01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479452bc44d5378309ee2abf1539bf71de1b7d7be3b5a0de05c24d96b1b9012d7a875feecf86924d7a8d98b00fd0b9b7768785088edb01a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000870892f443c80323836ab801837a121d80845c2bdd638c6e616e6f706f6f6c2e6f7267a08f47201b260e0e422100cebf3d61a6acdcc49f4a24e0b1e680e26f13bea9dc4e88bef16aef8812be32",
|
||||
"totalDifficulty": "8531065961847479229671",
|
||||
"header": "f90212a0113ba3b1153987fc483b01ccfe9ecadbdc36a7b264be75d6486cb6b694cc38a1a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479452bc44d5378309ee2abf1539bf71de1b7d7be3b5a0d91db5900e312a1ba8d39505406a95dc0ea20393b723c4bf488ade4e3c4ee4c3a05e63ab076852043b1c2fe010e2f14ab13dcc8e1c546ac497a24ce88c4abf3056a0b72e4a776f895459b6bf0937040990d868b1f45889aeaa26684e07472263fc31b90100b00200000063664554889124822ce2001022840543085d5810042382888542ca3816801780384384cd6851081cdc4d4b2b205a814b049198110a6869d60f4009a79c3854c9000581044889080000611c09142200106552000044027024004038092102814ed6c48040a8715851088a20108e80165f8c0c514019037a0000121304b2343416800b029000024404248238a06818414cb8690244879491855405026bc8250220520992c2380099d10024411c6048424083d1307822442d8444700405147883c4c041300aaa2408bb61084012983825a22830040a180106b5e27182088060b111515832902903a8f1d432a48004d0250437106a503491000048a91587067a897789f4d78371d801837a309c8379ffd7845c9d879e9150505945206e616e6f706f6f6c2e6f7267a0db22736cb3f06f9c86804902731fa6841eaaa1cd6326ea2a30e9c304d48bdd04880323b06837344cb8",
|
||||
"totalDifficulty": "9633968582330911261986",
|
||||
"CHTs": [
|
||||
"0x0eb474b7721727204978e92e27d31cddff56471911e424a4c8271c35f9c982cc",
|
||||
"0xe10e94515fb5ffb7ffa9bf50db4a959b3f50c2ff75e0b8bd5f5e038749e52a11",
|
||||
@@ -3598,7 +3598,235 @@
|
||||
"0x43b9d76f1c2bbab800dadc6ccb88b966ccda198e30068364cb9c0b9a346f5f03",
|
||||
"0x1c9ae4b3977a1d4969ef3d950d2c74548c8b44bcee652a65f7df128511b84e48",
|
||||
"0xa06a1a6ba91e429f805640faf789214f42be0d8d574065b7daea7daa37b05865",
|
||||
"0xf53ed26aeec7ba846e10a84814e7264197a0b2bf485c74d98e8315f0ddfd4b3d"
|
||||
"0xf53ed26aeec7ba846e10a84814e7264197a0b2bf485c74d98e8315f0ddfd4b3d",
|
||||
"0x57fa0c3eee29055cf5232125619ff171a60d2e8f0246af1ea8120969e03dc3f7",
|
||||
"0xeca0088d30058eac4ecb7ce8dfa454e46e642154b7851db0faa430a01bf33744",
|
||||
"0x3f43e499ddd06a059b192a9cb9881d15078157508c1ac30d687951454a22441f",
|
||||
"0xd99f60df5d3b55202089a3a69147e43a021c5760485e0899116f56060ba56a92",
|
||||
"0xe662a0a21e688b7452d0d5b6372bc8aeb00c589849f63da9c3fb4c280e6236b8",
|
||||
"0xcc83d5becb2f1580e7771c576b97709778a8502096948677f1274e9b0ff444de",
|
||||
"0x17cfc1a415766b30cfd1ecdb2bc8bca535928e1048803b9820e81d7058aa3b68",
|
||||
"0x8e1410621e8b0edbfd9c98cd1dac02e6b5dc8336da445cdb00c16c457ca27750",
|
||||
"0x3d8bc5d8acf9ff44f9099594290a91d47040eba0f766609f1dc034d6bb127f4d",
|
||||
"0xbc32d05ddd709d4f7ba929353a618d70b8eecbe1d3b06010cdc7dbf053569e25",
|
||||
"0x818d10c0a40a9675a1d87673d9dc55895b8ee337a0cdd99dda88d6c1d506a301",
|
||||
"0x633d32a1adbc08ab373324175e0205412bd17ed1be4ee5882d20944c3439f77d",
|
||||
"0x8107273c0ecc4179096f1492d21de076f84d0c4529ff6d563acaf85a8f5db5c9",
|
||||
"0x5d8c25ebc9468667d043926dc4a6d28caaa6be696ba3e4d248ab7150b20fd771",
|
||||
"0x5a8cdc39a49bff71df23eb7fb01811ce114edf6829f946a6155113b39480d023",
|
||||
"0x72f7ce230da5fe9ad521901d2e1f7c88a20c98ea82fc09c240501ba327ff3518",
|
||||
"0xc9c91729c335752f0e04f091dc181ce8659dfc13a77034b319c47554a5ff0bee",
|
||||
"0x3773c7671613b65b8c6fbedc97c96ba6e3b8a6cf64acf6d1947f2881dfec93b1",
|
||||
"0xb378b0953123036f313210f7e020441f41c81344b0437e5c947aa3d2e76cc357",
|
||||
"0xcf3b0163249f3b6d1c9b756eddcabc9fb9d11e121dd96499c750350dd56cfa3d",
|
||||
"0x8baa2ead915e991532ce72a856a001f7cc493a58016d3a0255cd416108357396",
|
||||
"0xf748b8ba84812b2f5ac3b91b51402194fe08c1d15382d10895fcc8d4622b58f7",
|
||||
"0x7ec5d0b6b989137882c20bebe11d2facc3e68e9a93a9b2c793d804d9e973304a",
|
||||
"0x4512ed8b4f3586a79c971cba695d727684c6485ccadfff6a3db45ff93fb1e1dd",
|
||||
"0xe6edc389d0ade0c7e558ffd357a7557af9f2d38b0b20c84a67936914acf088de",
|
||||
"0xf2947281385a9b2077e6e8657a6bdfb9c93f82311bd739d8e9b96bf97454ade3",
|
||||
"0xc768e9216d0dfa3da3fd3727ac4a673897567570653a8517219c079edd191496",
|
||||
"0x9bcb33bab81663ac501a5a4d2f3d739668b42a6bd2cf7645c3571d58b37c60a6",
|
||||
"0x540fda7f30ecbf8a61855b9619a139e502d8b9e1a3e72179f2399efb3aafab0e",
|
||||
"0xde605b760659834d38aa120d97d5b0721eddcdfeaa69a716e44b35ef721c85c7",
|
||||
"0x8979afdd57a677913bfd414f3c7cf88c3c7144f5168476e7c08518396cf8134c",
|
||||
"0x6826b8b3aae4d8f97707e9751a4313738ad42861bac31090afb77a34f7214b7e",
|
||||
"0xade12591565e41be9e81ac8a673324a680b0a9e6d980ede210c966b1b9252938",
|
||||
"0xb2f3710b4e6c805bd20ad93fa0f254bd645b5c9b5fa299f1f8f9bb57d299e21d",
|
||||
"0xdb80cf61e5a9d6b6237855eb518851f474d12db1fde3c534762e1f7d9367763f",
|
||||
"0xc40c3599108f6057fb67f09e7aee418490af2a887d59f428af222519a7c03a12",
|
||||
"0x0916f11f929196f5834bad46ea7eaf55716ec2d269aef9f486cac38fa7734831",
|
||||
"0xd5362e4d43e3da51e12debe7966c2a06ae0fdd327cff666aeb7185b5d6cc71e2",
|
||||
"0xaed4937eb0e5c9a5e6803cff864691f7ac63fa9f82d3c2e1ec9a2777d4d3f263",
|
||||
"0x49f63292bb091a6d6e6515e5f822903da4a9e652847a7de5b0fba5ca69336ae2",
|
||||
"0x7347591d5dc652262db2e95f65a570ae894f28a631dace959f6264027ae5f3c3",
|
||||
"0x300ebb8f363f2921f5baa4ad46332bd7d10eb113679afa0851ede28a33ce62b7",
|
||||
"0xff1b93baa7285220352ab656d513ee19c12da79c0c87d2035c148744164cf32f",
|
||||
"0xd1793b3309372878fea3c14f2e4dae39588ddaa2396fe246b3c4cdb534a167dd",
|
||||
"0xe2c7d728bb7899ab8b0ae0d07d585cd380a38f63fb9079532419fb5cbeacbe01",
|
||||
"0xc972d3a0a76889c41d1130c52bf175526a5560d2fab7b28bba7c914a9b9621cc",
|
||||
"0xebd731a2040b488d736e846efdb41ac5a6020e7c2b287249c105c71bf59b9504",
|
||||
"0x8745a726f0e971fbe22c9b28234c3d93333c0f8d5c126ff9ee5000e26da7031b",
|
||||
"0x3033928e0f79cc47d31814e409312127ef73a15a6aa915786e4410677942dc6b",
|
||||
"0xeb77e57fc7de01107d1adfbf479a4c3a6ab5ddd008dab67069c5fb488551634e",
|
||||
"0x6eae31a9b04e7d30e7781e33323f52e9f411fc7143b8feeefeb71cf6b4e86081",
|
||||
"0x39ac81712892e1ca0cec0b63cb7d526edb0a276e6ff41369288f788d4eeff7a3",
|
||||
"0x9de1c4046104a2bfe58e94215f59e1ce5898e3efcaa2ac6a7916817648e3b304",
|
||||
"0x3d6fa25cdb3aa2cda4bf65a85927fa5b5c79d3ca427b6b128d34dd24aa08b5aa",
|
||||
"0x8f5d95fb92d3eedb02da88535e4d0c9ed713fb2a6ded42ad8d2036306abd3b31",
|
||||
"0x36abaa49a58fd335ecfe8b0ec61a68da28af30833018788fb710c3847dc3e258",
|
||||
"0xe0224a4df20ed2e5cd78db19cd906d29bcf3aeb6f79135aeb62be16f766572ab",
|
||||
"0x7584341a036595e957e7f7c09a5932c1e75e5a5a73ccd31fc2806b134a899082",
|
||||
"0x1dd6909a77af37732b2e59d4341047ad85b610f470684433f2929673399c2fb0",
|
||||
"0x5d9bf04171804ff9f2927a14176988349c0d0a86654d8a5897ada06ca4a18d02",
|
||||
"0xa1714a70cbbaffc82a9018ec48acd7aaa70a5b6ed00800249fdd76326c5eb32a",
|
||||
"0xb8fe04ca47841ffa34b5f17ce8922c86a9b98bb6d7d13c4b0fd27df931200422",
|
||||
"0x308d034f42f0beba3aedda196573bff7b9c9852888d6f9e3362b4259d2c1cbe0",
|
||||
"0x05be7b2c1b9f84273af920a4af58b183619b016aa20199fd6845eeacc479c744",
|
||||
"0x613880fff823c896127092c2c4e0319e6cca955b650829ffa053c4b228429d61",
|
||||
"0xca039f943e38b017fafd119e870ee80bcd19e7994b15449a03b7bf35c1a69add",
|
||||
"0xfe29c86d46c9db3f2332f2109a81199c5f48730826755b56715a98eae6e6bef9",
|
||||
"0x6e95261130af62956647ad47ebf45dba97a9dd684940d5b241a6b0cc36fc0b45",
|
||||
"0x113eff6173e9551800e70882942c37723aa83d573f2349ac614e6d245411af19",
|
||||
"0x07e9fbe087e6b8f4a2cf41373b1977823875a9d3be56b937b977503a20996437",
|
||||
"0xae0792daa47529f8690d30dddb9e0ccbdcd3e4a3b3f0386f098b147c4cb3dd58",
|
||||
"0x6ad953988a96ea288c407afc70581289c4dd6b8ffceda65f6d4a51e8cb7228a8",
|
||||
"0x949d0b15d25fb79f31900f0e48ac3fef50b3d1b69f24f505fad87ca56ad883ca",
|
||||
"0xf0e01643fc4c21dc3adb6dc1a0bc9f601af1bd4b5ed50ba156a280996d521db9",
|
||||
"0xcf396c2e2018e5dc71ce2e8d8d2716565fd9ef6ae097b871b4349a487e0a6727",
|
||||
"0x5f22e44bdf7a346985839c4a395f66e2fbed238f0463ab2b02d7dd23c4e25748",
|
||||
"0x8808ab6e652afa85738443a808d140c103757cd1a356bbe2b409e95cced6fa7c",
|
||||
"0x9ab3eb50f50a357020c69c9501cb2864febf0be1c04edd20cb1fce3fc075b7db",
|
||||
"0xc360f24716b701218d2c486938e17d7b56a85b818b4e808f7c12c85778914f68",
|
||||
"0x0e8388813ad36963923d68e9a223087e2e29282dec830d13e04ca444a6e1ed6f",
|
||||
"0xf77bc7d25e80792e69d8900f5e77a9eb276bc13d391720c8b8a1c608deaca05e",
|
||||
"0x0979a99fa0f1a046c1da8204f2912b3c09c6dc7d37e0b6dba11935e5af8b1fb5",
|
||||
"0xf9327d2fb74c22853685a3d41d6f63984a354115af69c7873650c9f8bc2d31ba",
|
||||
"0x9fa02b5ef88c4496cd054f6dd26f292e389976b38a22760cbb505f068754a60f",
|
||||
"0x1dff7dbca8c5d169d2ad52a4434a01ef647f29707e59d4543053a8bc7afc664c",
|
||||
"0x051dc8f86a07ed084afe4d14f0b39268fc5858c908056401586acd0c9bd628d4",
|
||||
"0xe6776e7bffe6398d66564b7e5993ef70c7347287842319e585c7f844002d9555",
|
||||
"0xc5bc5e2c1e26900fe2492019e11bc4ec5595e1c8eb68bc1ddde65aed94ab83b1",
|
||||
"0x6f868ac5f8f7071b3742573d8f4a3aea1bff632f6c5c15988572ea1983e9e535",
|
||||
"0x086a27e853ff55ef97cf876e0d703898eaa0769ee4efadffacbb8c03de35657e",
|
||||
"0x00aa9b9ffb2837aec2fd6444802437a5dcd4654ddc2df584e1ca351832a9e163",
|
||||
"0xd395a77dd37f2e397456a5385e1fe4e781458db37d3a6d8da3b1d5fb7c5558fe",
|
||||
"0x7567bd55454dc888c6aca9481ac1fd6641a93b3d2f5d1bc81bab97dd78f490ad",
|
||||
"0xb7e980a03060221442dc0f9487a6f0614f5b83ea23350d2de3ff0ae4e93d02a6",
|
||||
"0x1b43c09f68af74141ab23bcc3402932257deece48af74503e6ca452ecd59d9a3",
|
||||
"0xfde1e03da25883b8eb78e3ac92914feab4e7294eb78a94e801876d59aa559f8b",
|
||||
"0x807aca1ff5c2132a7c2b5d67de9c536968755dcfc32e8873fdd296f807148d56",
|
||||
"0x8f3160048010ee14d59c26c0c2767b78350023327534ca27b086feea4cde5910",
|
||||
"0xb26f5f50bdef8212578eb07f7afb52785944811975e1671a405013a0fcfb88cf",
|
||||
"0x4e14680b46a09bdf8b9046f62ec5a28b8edd5704c3cc91fefb83646a5dd3eee9",
|
||||
"0x792f84baa0644328b9cf5af899a154faae97fbbae7a1e7874e6219085b271265",
|
||||
"0xc4d26ab903ed6478fd9a0fa80382f7b4eecd25125b623c6dcbc4ebaf0d8b3fc1",
|
||||
"0x906b46aba1de6a6e3692bea009597d0a8dc40b76a1c5a4476a9daeeed65c2b25",
|
||||
"0x167fb1cbf8026a1af6c16ff3b18285dd9d934158a9b9ae75b90ba7895ca2b7c9",
|
||||
"0xaa659098a8ed4e33e511872bc82cf758eb6c2b47e318899b4e4385bd32fae051",
|
||||
"0x757c86586e3307882c6d966c2a88745e4bc1a9002337a5d137d83ef3d4496768",
|
||||
"0xf342de6ecb6bb5579cfca4e7dd4dedd2c1a685287dcbd891fb918226eb82cacd",
|
||||
"0xb025cb5c7c1d64a8138ddd439aa95cd9a4c1162d628dae1f09bbf8a225a49f22",
|
||||
"0x6ab070192b7919718111a5b1d74862c48a5705d4e9c6b47a3a81564180c3526f",
|
||||
"0xf9a23794eddea371183902ae36ae4b54387b4b8b170bf848dc24a5ea39649545",
|
||||
"0xfb9dfb946dd83814681f93091ceb299d417d8ec8d28e2ddb7843d913b699a6a3",
|
||||
"0x44ea56c8eabaaef19c9fde38ad0f92c074039d93960b51238c1b11ed2315163a",
|
||||
"0x66f8ce000b102ea085a18cfb17e99f242e0458d0b0d9d39b6a8653008fdaa98b",
|
||||
"0xd573e736c4609d90ade296503843c9a12ad8f3795eefb32635dce70f2fb17381",
|
||||
"0xa783abcf83917308a63bee26ef64b010e15b62014ed560881adc3ce78f80c3b3",
|
||||
"0xf8406110d71475627fa02fe434b3270c353eca0ea700bd196a9c42dd2e6c472d",
|
||||
"0x5e3350f159e6370a741af5879bdcc8b08c44538dabd162fef2b745e9ff2828c6",
|
||||
"0x915c517a16a1dc3095bfb9550f24afc3a60f442c9205a7ebddc7eed37fb267e7",
|
||||
"0x9ec7f72f0e8d5509e3ec337b0c879f730c16c55e4259526c0816d6891feb1dc6",
|
||||
"0xc294284cac5de499512f9b12707b5f66dbb3b635c1cc6d4419b17f40e272e339",
|
||||
"0xfbda44ddfe4b7c31b915fa94a27aa01fcfb22a9fcf0b557f9788bbf48b3f7f32",
|
||||
"0x4418fe011a16af7da4645f300143a6cb005650ea96ce23c6adb4a82f60f72beb",
|
||||
"0xfd3a00e52f4cc05610976b0def190199543ff3e423f09f8bbe5cef8315f36d7a",
|
||||
"0x5c9fee100da6ec53ab1cf96ca9f369401853753eeaea30bef75f6989faddc504",
|
||||
"0x713e2e28396b62bc63ab0a3dcfeabe977bceece4057a687d157320358f2dd08b",
|
||||
"0x62ba90cbd06efea1d7bb7128e37e33d94a21b246b7eb7159d2708b5552247a75",
|
||||
"0xe13d2697cfeea63e973c7493b4c54917a639fcf13eb1b327e02acee353bf84bb",
|
||||
"0x8ed199e2fd654bfc9dfd5e7ea7dc82bea9f4535eb480c95984a5a6bc1533bf8e",
|
||||
"0x4e5475dae57c548460d4ddd15583223bf2a4a2046c2ee56ca670892794a37d90",
|
||||
"0x80409971b3e59ec71deb1a158a92ab6fe8318cb9adebcf583586e23e42d370c4",
|
||||
"0xeb35d7c78965874110f67b77307deae4bb29dc98c01fbac3737409ede61df7c6",
|
||||
"0xd358b672db99b007ac54ef3ea7c77c0eb0b4e9cc1437ca4eb70d71aaaf84b6f2",
|
||||
"0x0ca4c79c1709b947794ae73dd3b73b357273c4e5cfc83ec85c4c2b649e10740f",
|
||||
"0x704635b2335b5ad2be0e586e60770dc1e0548794ee2c1670cbfbc2ed0c1f64ae",
|
||||
"0x6a6f2425c865216b49e7e73026fd2e9cc02f131c0050ce849f274c37828909f0",
|
||||
"0xce31e62ac098db0fef0823941009b826d4e5b8e11f2e01208ee6abccb160c0cc",
|
||||
"0x5669c0e6ccaa8abff08e944fe8bdcf0001dce9c10ef8b90d7f821819e028dcb6",
|
||||
"0x37b59281d4eec501ed45d68c2bfac450d336ee5a18ecb7d2d812763d2cfd4321",
|
||||
"0xfb52f084a5ffd63001f47acdb2ea62e91714af63f896c151100350d83bd2c7e4",
|
||||
"0x67bfc4a94fde6e81b54ebe52914c0d73a053bbac22d6d64862e987e53c78ed61",
|
||||
"0x49c141a8ac1124f40d06c569f49363a8af092d0028b02d8f4c895af2f86d0f28",
|
||||
"0x5c81c85021692d5dd1bdbd3a4543ec86d49e674380a0e5f59d4400902d7e753b",
|
||||
"0x9b46d19b0cee63461453a487bbf855fb4a7d70933ce2b7445d1dce8dbbc11cf9",
|
||||
"0x50fe5cb0ddf34ed2ee8341848bc00df89fda05fbf0ebb1b34d12afe9e5ae4d1a",
|
||||
"0xd56b4c4880798175c2db50c5c5d6845b5c1e7b6b33172ba107f5de075ed09def",
|
||||
"0xe0928a4092e5ab5b9a34a8748c3ddf86a6a9ab50e85777c4e1e8088ac7b44ae7",
|
||||
"0xfcde6d53ff8286afecafa27d608e94c07a4d78813edeccb73a1076772d1f7e83",
|
||||
"0x1bff0dc76b0d8877a9ea133a023a5dc0f88559f16f0adffbf7b4d58b6be487a1",
|
||||
"0x5252a71f6c9784b538ecd810bded0520f349f5aa748657a9b4422474eee08388",
|
||||
"0xc4cccd5ae51babfe8e9f76af2c64227b0fd63bc2f4336b7820a32846516d9835",
|
||||
"0xd07bc360f06a492a13047247448ba37fc9a167bd81ee63607976be269d245e14",
|
||||
"0x9499022a6b509dd05eae2a7c799c332382b810843065e82ec72891b771cc3a8a",
|
||||
"0x0ba258fb2666908035e53ec37a96ee13719779de43f14a57223b704961ef667a",
|
||||
"0x4dec79cac5e3b414aa835c69bb2c580ccc03eaed675b61070f37b606ff4715bd",
|
||||
"0xac640ffa67870bd91b1ff36450256fb1e5f59e65f4ef844875185c38f7f986b5",
|
||||
"0x0af93eccdfbb75dc353ff31949329b3c96ffa93f63e9ae4a515f6e177e201d35",
|
||||
"0x5a2d5ba9defce6db1bff0bbbe4eee170fe3b9c0ecb4a1ec6e16f904b55c07beb",
|
||||
"0xd92f1c26de95255b1e0926341c35b5bfd106820dbdcb381400516d247062f3fd",
|
||||
"0x447ec0cf1a32e8201cb92d0ad13adc6e664a07612bf38ce9c598c799cd947fb1",
|
||||
"0x28460192df35aec41fe3992efc94da904d69e4b65e518fd2c530b38c1ec88819",
|
||||
"0x6b0557132b0efe568a96f77fad4f1e18cf05670c007488052f347cf3461ee98c",
|
||||
"0xb82f3f400a0edc100ddd6e82c2ea587eb5d56ea0f8faa379f8fa259f31ea0838",
|
||||
"0x370b650e0bd14d9e5d749f628fca91ff47184473b6cba948e9ad3492a68bed5e",
|
||||
"0x794e423feca451babc044923a79ceab62ff3a9a7e8947dcadd0d91f78a11cff6",
|
||||
"0x7fe410432bfc7048e6685eb6bf0b4ae9808864a2e09ed1d373dc211f40c59da7",
|
||||
"0x9f53d260f145de7b48c04829abd97989bc11d748af7d119ebf56948ca438913a",
|
||||
"0xad5ad5cd5ff452e16c07bba12f0b34bb1c3c8c33d54db45b515cf6761d6a1cc8",
|
||||
"0xcc6e322ea2c52af09d720524c85629019eac5ca01dcec5da887ad4b32157b9e4",
|
||||
"0x5d3ddb9fa275898453e8430b26270e2812709717898683f0a3291291b29d688a",
|
||||
"0xeff621bef47694a862a320a661b691b491e4a5c44e1d2026c9756f84903a6375",
|
||||
"0x110e7059d20e4531323dcf981ad6cb9d67d56815c54394ab1b0b7af4235aa218",
|
||||
"0xe44d27931b9429204cd2e9cba838f0ed707d5668ab55ecf2c906b2748fa1f16d",
|
||||
"0x9d7166683764cde8445c58697df637cd48e35b3ad00f6e6d4bbf12844ba217c5",
|
||||
"0xf5f6625754100a91cd7283d47e72cca73c39e5fa2e0405d427430bccd49cc2bb",
|
||||
"0xd6b27ee81a557ff5d8947225c19f3ba023af18415a413acdf438548b24902427",
|
||||
"0xccc665895dbabf0d8775c5fddf167b41579b0e6bff8fe99c8da00622334c8861",
|
||||
"0x1986e5fd526af0a0e74ab83cb82c18dbd5a73fe72b94c8ca10318f8f6bd2d98a",
|
||||
"0xd3f245d6f37b0c47506fc4a2b12d85ff87eb35c2f45f82c3e5bebdc7362d8cd6",
|
||||
"0x53b97494c77ef9a843ce61b2a58231bc145b492b710fc3dcf79c297187993bbf",
|
||||
"0x00d4cd1f9460a8625ed0a539257e58a9ab8051ff239172f0a9437cb9f0d1a11f",
|
||||
"0x1c3d92f1e67b04c24db2eb04184ca7ccd5533540aca4dcbe084a70648c347ee5",
|
||||
"0x200e39cb704bcda42f547c0cae54c0dd4c0b1aaf17469d69deaa67d3ef0d95c5",
|
||||
"0x5aa208366dc50c2e9f0075b0e8aad396851f54a42c9ec1114c2994da0c2fcace",
|
||||
"0xbea70811c324fb1553c4fc492521ce062756da0a469d8f98cd6c0f7a3a7b5e3a",
|
||||
"0x79aa191ef9975049a5f2b8b7e2921a3f78d045b99b7a569a93680c5ee2600a18",
|
||||
"0x233fd477509141aed423948a0c5c5b8f0ab8cc3c4836c0f44c8cd6c0811b419c",
|
||||
"0x1737e144530678804416cd7c3c8200f54f395bf7712c9ade8340988e1e123af5",
|
||||
"0xbdad2ae32cbfc13446adfe9e4101f32fb52b1e336c165a1125c917d6c1a1fceb",
|
||||
"0xc20dedeedd63be4c10d92d9d0e7b47e20d503f331cb31d47ec9e99b915305ba0",
|
||||
"0x262281f50e2892d8cfca3b8f8a6645b5931fb4601755f02fb863d719cd690381",
|
||||
"0xb0a717f11ff1e3f1a4bd775792c7e5a75af6e56967ab1615be6b4941ca9315e3",
|
||||
"0xe8f45b1aee0fb0e87148b316ee0ce662ae3bb2abd05e9666429fcf30893641b1",
|
||||
"0xe7a439e2577c4f892921f798efa19353d236146b849c20253b07f03194b36286",
|
||||
"0xf4eda704d4864d8fccefecc246fb683dbdeee5468a53dd11d71d71477d170422",
|
||||
"0x308d977f739b7a8cb4810242fb447a8f6cad45389a127f5822ca2df48fa9df86",
|
||||
"0x3115d6d0f174e00bf3e5704f57e44b62f7e279894ce62f39568ffe4367fc5a44",
|
||||
"0x6b6e6354b8d1e1ab0430fe2a5068b2b2263ff453676dbfdce5da60a6d625f20f",
|
||||
"0x9b8a7b122572f459d946e67a1c78973040bcf67a64327f689d4016c53afcc4cf",
|
||||
"0xa367c0bc2e6029afec518db94fa79288801f5ebf2cba50980fc9754a40784d19",
|
||||
"0xc1a017142eac944b5fda4cd66a9b6b6dc64551c3ce958e8811797433b96ec5d8",
|
||||
"0xc9e3999a3f162d42ae52644ce4f765b5ccc7fe2a4c91cc59048eeb8c8086718e",
|
||||
"0x67c135523c9703aa1f1b653d9279804af4cd81cd3de99e10a853b42d78143914",
|
||||
"0x9af2390bb01b245c65f76454f1c80102871131417cc8fbff4b1ada056d04dd47",
|
||||
"0xf4cec7d4f4a76c769021ab0dab848d668fd36e910259e45094d88defabd13448",
|
||||
"0xe2a224fd4510ac5f8a6782d2eed14ee164e6bb92d3f0a7e5e71497046fe9f30c",
|
||||
"0x9884ca2b5533c36e03fecf28470fd3c45292dc623fb220c5eb0a580781fbe724",
|
||||
"0x078b1365c5dc77fdea6bb010fab6c4dede06e27386d4d5f205bf7e7857b03865",
|
||||
"0x8f930fa645409fc1d7fb28637360489a5e5eaa6554857441c3fd8990243d9972",
|
||||
"0x2e21ac485ed90007e8b69cf247c28b25361729bcc7501a3296f9c06dd0742888",
|
||||
"0x46c3ea9e86ad55d87b6f5d50fd9c145bcb6ca90a4d570c1f86b5532b0762d8c0",
|
||||
"0x87edc87f5ac353d64b0f157ce3e3180ce73fdd1f0ae9db1406e49581f1780de7",
|
||||
"0xc940108991c82f871c3eea33ec93951c9bc33cd0aba1c77262cb6fc6ea16f4eb",
|
||||
"0xba2f1d37cebd9bcde635bee4c0f260af8fddb43a84508f244b562dd1f7bdbe92",
|
||||
"0x738e8d02870cf37ba27db2eb621d5f7b32a225010de41e3983ed389ebaa0e364",
|
||||
"0x84af8e6e7ceb53e068bdf16091bfe966458bb5d3e4a925360411a213aaf46a5c",
|
||||
"0x548302ac8a0af1ef5bb91d469f66f8669cdb2a07c432e7504a806e00487adb63",
|
||||
"0x35bc3a284170d090e6fe053d3bd2a8fc3aa299d113b69b90340ca4c7e019016d",
|
||||
"0xfe7b61c4388f2615642f9ffb44279f31a98c0f0d2f3f37b5f77ba09a67c12737",
|
||||
"0x864581a4e526055847c252f6169bc54b5a1615de8e1cb7e80c649315b04a9aab",
|
||||
"0xb8b4c67301cf9d3e91ae59a0394c8085737358bde297c58688b48a9d33c04205",
|
||||
"0xa1ee0d1c7d50d37f96505ed06b166722f47fdd784b71bb3d47539ae40be96262",
|
||||
"0x63b2658609397ec6a9e9d9d0a5b318b79b1e39348606ca53e0f84f6466d3aad4",
|
||||
"0x2211abc4f8bbd6784aa191805465b10520a6c505d6257063aa9b911d5781fb89",
|
||||
"0xefed35d1327328deece22922f08d3c3931c80c1ea9a8bc719b8226f38823bb6d",
|
||||
"0x64b862e2d5a6c24d569f3352b8524ebfecfd5a3205a3200ec78df72d79a66838",
|
||||
"0x6da8edf169a9c78307258a723c1ac1d96db20a7131018efad16f0606683c0f07",
|
||||
"0xbae1427beab8c3e71cea57e5f9cdd55bc278c6d6073ae2628f0d3efbf9894a42",
|
||||
"0x389bbd1b3fa390e8d3339cf5b018ec64d9cfc02bbcb801acad0857fe377ed83b"
|
||||
]
|
||||
},
|
||||
"nodes": [
|
||||
|
||||
917
ethcore/res/ethereum/goerli.json
Normal file
917
ethcore/res/ethereum/goerli.json
Normal file
@@ -0,0 +1,917 @@
|
||||
{
|
||||
"name": "Görli Testnet",
|
||||
"dataDir": "goerli",
|
||||
"engine": {
|
||||
"clique": {
|
||||
"params": {
|
||||
"period": 15,
|
||||
"epoch": 30000
|
||||
}
|
||||
}
|
||||
},
|
||||
"params": {
|
||||
"accountStartNonce": "0x0",
|
||||
"chainID": "0x5",
|
||||
"eip140Transition": "0x0",
|
||||
"eip145Transition": "0x0",
|
||||
"eip150Transition": "0x0",
|
||||
"eip155Transition": "0x0",
|
||||
"eip160Transition": "0x0",
|
||||
"eip161abcTransition": "0x0",
|
||||
"eip161dTransition": "0x0",
|
||||
"eip211Transition": "0x0",
|
||||
"eip214Transition": "0x0",
|
||||
"eip658Transition": "0x0",
|
||||
"eip1014Transition": "0x0",
|
||||
"eip1052Transition": "0x0",
|
||||
"eip1283Transition": "0x0",
|
||||
"eip1283DisableTransition": "0x0",
|
||||
"gasLimitBoundDivisor": "0x400",
|
||||
"maxCodeSize": "0x6000",
|
||||
"maxCodeSizeTransition": "0x0",
|
||||
"maximumExtraDataSize": "0xffff",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID": "0x5"
|
||||
},
|
||||
"genesis": {
|
||||
"author": "0x0000000000000000000000000000000000000000",
|
||||
"difficulty": "0x1",
|
||||
"extraData": "0x22466c6578692069732061207468696e6722202d204166726900000000000000e0a2bd4258d2768837baa26a28fe71dc079f84c70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"gasLimit": "0xa00000",
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"seal": {
|
||||
"ethereum": {
|
||||
"nonce": "0x0000000000000000",
|
||||
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
},
|
||||
"timestamp": "0x5c51a607"
|
||||
},
|
||||
"nodes": [
|
||||
"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": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000001": {
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "ecrecover",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 3000,
|
||||
"word": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000002": {
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "sha256",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 60,
|
||||
"word": 12
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000003": {
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "ripemd160",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 600,
|
||||
"word": 120
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000004": {
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "identity",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 15,
|
||||
"word": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000005": {
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "modexp",
|
||||
"activate_at": "0x0",
|
||||
"pricing": {
|
||||
"modexp": {
|
||||
"divisor": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000006": {
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "alt_bn128_add",
|
||||
"activate_at": "0x0",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 500,
|
||||
"word": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000007": {
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "alt_bn128_mul",
|
||||
"activate_at": "0x0",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 40000,
|
||||
"word": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000008": {
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "alt_bn128_pairing",
|
||||
"activate_at": "0x0",
|
||||
"pricing": {
|
||||
"alt_bn128_pairing": {
|
||||
"base": 100000,
|
||||
"pair": 80000
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000009": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000000a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000000b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000000c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000000d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000000e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000000f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000010": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000011": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000012": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000013": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000014": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000015": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000016": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000017": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000018": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000019": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000001a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000001b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000001c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000001d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000001e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000001f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000020": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000021": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000022": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000023": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000024": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000025": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000026": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000027": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000028": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000029": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000002a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000002b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000002c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000002d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000002e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000002f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000030": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000031": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000032": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000033": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000034": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000035": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000036": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000037": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000038": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000039": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000003a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000003b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000003c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000003d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000003e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000003f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000040": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000041": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000042": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000043": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000044": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000045": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000046": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000047": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000048": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000049": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000004a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000004b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000004c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000004d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000004e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000004f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000050": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000051": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000052": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000053": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000054": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000055": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000056": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000057": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000058": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000059": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000005a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000005b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000005c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000005d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000005e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000005f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000060": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000061": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000062": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000063": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000064": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000065": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000066": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000067": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000068": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000069": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000006a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000006b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000006c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000006d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000006e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000006f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000070": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000071": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000072": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000073": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000074": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000075": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000076": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000077": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000078": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000079": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000007a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000007b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000007c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000007d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000007e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000007f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000080": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000081": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000082": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000083": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000084": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000085": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000086": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000087": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000088": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000089": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000008a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000008b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000008c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000008d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000008e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000008f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000090": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000091": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000092": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000093": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000094": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000095": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000096": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000097": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000098": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000099": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000009a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000009b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000009c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000009d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000009e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000009f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000aa": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ab": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ac": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ad": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ae": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000af": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ba": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000bb": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000bc": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000bd": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000be": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000bf": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ca": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000cb": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000cc": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000cd": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ce": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000cf": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000da": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000db": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000dc": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000dd": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000de": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000df": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ea": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000eb": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ec": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ed": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ee": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ef": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000fa": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000fb": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000fc": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000fd": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000fe": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ff": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x4c2ae482593505f0163cdefc073e81c63cda4107": {
|
||||
"balance": "0x152d02c7e14af6800000"
|
||||
},
|
||||
"0xa8e8f14732658e4b51e8711931053a8a69baf2b1": {
|
||||
"balance": "0x152d02c7e14af6800000"
|
||||
},
|
||||
"0xd9a5179f091d85051d3c982785efd1455cec8699": {
|
||||
"balance": "0x84595161401484a000000"
|
||||
},
|
||||
"0xe0a2bd4258d2768837baa26a28fe71dc079f84c7": {
|
||||
"balance": "0x4a47e3c12448f4ad000000"
|
||||
}
|
||||
}
|
||||
}
|
||||
857
ethcore/res/ethereum/kotti.json
Normal file
857
ethcore/res/ethereum/kotti.json
Normal file
@@ -0,0 +1,857 @@
|
||||
{
|
||||
"name": "Kotti Testnet",
|
||||
"dataDir": "kotti",
|
||||
"engine": {
|
||||
"clique": {
|
||||
"params": {
|
||||
"period": 15,
|
||||
"epoch": 30000
|
||||
}
|
||||
}
|
||||
},
|
||||
"params": {
|
||||
"accountStartNonce": "0x0",
|
||||
"chainID": "0x6",
|
||||
"eip150Transition": "0x0",
|
||||
"eip155Transition": "0x0",
|
||||
"eip160Transition": "0x0",
|
||||
"eip161abcTransition": "0x7fffffffffffffff",
|
||||
"eip161dTransition": "0x7fffffffffffffff",
|
||||
"gasLimitBoundDivisor": "0x400",
|
||||
"maximumExtraDataSize": "0xffff",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID": "0x6"
|
||||
},
|
||||
"genesis": {
|
||||
"author": "0x0000000000000000000000000000000000000000",
|
||||
"difficulty": "0x1",
|
||||
"extraData": "0x000000000000000000000000000000000000000000000000000000000000000025b7955e43adf9c2a01a9475908702cce67f302a6aaf8cba3c9255a2b863415d4db7bae4f4bbca020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"gasLimit": "0xa00000",
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"seal": {
|
||||
"ethereum": {
|
||||
"nonce": "0x0000000000000000",
|
||||
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
},
|
||||
"timestamp": "0x5c2d2287"
|
||||
},
|
||||
"nodes": [
|
||||
"enode://06333009fc9ef3c9e174768e495722a7f98fe7afd4660542e983005f85e556028410fd03278944f44cfe5437b1750b5e6bd1738f700fe7da3626d52010d2954c@51.141.15.254:30303",
|
||||
"enode://93c94e999be5dd854c5d82a7cf5c14822973b5d9badb56ad4974586ec4d4f1995c815af795c20bb6e0a6226d3ee55808435c4dc89baf94ee581141b064d19dfc@80.187.116.161:25720",
|
||||
"enode://ae8658da8d255d1992c3ec6e62e11d6e1c5899aa1566504bc1ff96a0c9c8bd44838372be643342553817f5cc7d78f1c83a8093dee13d77b3b0a583c050c81940@18.232.185.151:30303",
|
||||
"enode://b477ca6d507a3f57070783eb62ba838847635f8b1a0cbffb8b7f8173f5894cf550f0225a5c279341e2d862a606e778b57180a4f1db3db78c51eadcfa4fdc6963@40.68.240.160:30303"
|
||||
],
|
||||
"accounts": {
|
||||
"0x0000000000000000000000000000000000000000": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000001": {
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "ecrecover",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 3000,
|
||||
"word": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000002": {
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "sha256",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 60,
|
||||
"word": 12
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000003": {
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "ripemd160",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 600,
|
||||
"word": 120
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000004": {
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "identity",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 15,
|
||||
"word": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000005": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000006": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000007": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000008": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000009": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000000a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000000b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000000c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000000d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000000e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000000f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000010": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000011": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000012": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000013": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000014": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000015": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000016": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000017": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000018": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000019": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000001a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000001b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000001c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000001d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000001e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000001f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000020": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000021": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000022": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000023": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000024": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000025": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000026": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000027": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000028": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000029": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000002a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000002b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000002c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000002d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000002e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000002f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000030": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000031": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000032": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000033": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000034": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000035": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000036": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000037": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000038": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000039": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000003a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000003b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000003c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000003d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000003e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000003f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000040": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000041": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000042": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000043": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000044": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000045": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000046": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000047": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000048": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000049": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000004a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000004b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000004c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000004d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000004e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000004f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000050": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000051": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000052": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000053": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000054": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000055": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000056": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000057": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000058": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000059": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000005a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000005b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000005c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000005d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000005e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000005f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000060": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000061": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000062": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000063": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000064": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000065": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000066": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000067": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000068": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000069": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000006a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000006b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000006c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000006d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000006e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000006f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000070": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000071": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000072": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000073": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000074": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000075": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000076": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000077": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000078": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000079": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000007a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000007b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000007c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000007d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000007e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000007f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000080": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000081": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000082": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000083": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000084": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000085": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000086": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000087": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000088": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000089": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000008a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000008b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000008c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000008d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000008e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000008f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000090": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000091": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000092": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000093": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000094": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000095": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000096": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000097": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000098": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000099": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000009a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000009b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000009c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000009d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000009e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000009f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000aa": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ab": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ac": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ad": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ae": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000af": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ba": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000bb": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000bc": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000bd": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000be": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000bf": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ca": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000cb": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000cc": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000cd": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ce": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000cf": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000da": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000db": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000dc": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000dd": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000de": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000df": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ea": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000eb": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ec": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ed": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ee": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ef": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000fa": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000fb": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000fc": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000fd": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000fe": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ff": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x25b7955e43adf9c2a01a9475908702cce67f302a": {
|
||||
"balance": "0x84595161401484a000000"
|
||||
},
|
||||
"0x6aaf8cba3c9255a2b863415d4db7bae4f4bbca02": {
|
||||
"balance": "0x4a723dc6b40b8a9a000000"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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",
|
||||
@@ -64,8 +78,8 @@
|
||||
"gasLimit": "0x5B8D80"
|
||||
},
|
||||
"hardcodedSync": {
|
||||
"header": "f90247a0017c9292a6abf6bb9aa48c30f8854dc0e9649bceaf19079b1aac50ebea4fa316a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794007733a1fe69cf3f2cf989f81c7b4cac1693387aa06b81f6633226562f466201f0d097877c903a650f7427aefa7433fb971f601287a0098141509099d91ed2c2e503d43db5b5412d51880994e8e03a86e1d7a9ca8e8ca0495f318f8bfdd4beb517d115ad5d5330aebafe70eb2b1cfb0ab029221a0f48c1b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090fffffffffffffffffffffffffffffffe83975801837a120083035108845c2c49e49fde830202058f5061726974792d457468657265756d86312e33312e30826c6984170b1279b8413ee0655a59d1f7f8db39c22055c614346450e99965fef62efa43b21b20f0966e3e41eb65fcaf6f9ce3a34359dc064827e06f3a29d2c717f287234785d369e56f00",
|
||||
"totalDifficulty": "3324635628632492920129912637269655024947201711",
|
||||
"header": "f90247a0d0c0f490e8e5045fa96fd77ce45ed983900feaab964b2b0ba3a2d3a6b5e0f842a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479400d6cc1ba9cf89bd2e58009741f4f7325badc0eda0c91e59c81193c4fead4f64ecaa349e97056409dfbb787772ea3c1e55e7582b2ea08be1332f5e7eac286c7e5e5ccf3760e47f4a919548c15e748ad4351bb8405f9aa054e0533aa3433f4d07afa226230c867fc1e2844b5f49b25aba8df17630d9f8c8b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090fffffffffffffffffffffffffffffffe83a26801837a12008306f78d845c9da0b09fde830203088f5061726974792d457468657265756d86312e33332e30827769841727682cb841d6db93a25c84287603ee26e48db0dd301753840cc7283d411d3febd0485e02b2520086bebfb3aec1ab69403f45f0d59249bf0d458f33aa268dc4badefc73c8d300",
|
||||
"totalDifficulty": "3571337622391237938633151520660827524104528124",
|
||||
"CHTs": [
|
||||
"0xdb9557458495268ddd69409fc1f66631ed5ff9bf6c479be6eabe5d83a460acac",
|
||||
"0xd413800c22172be6e0b7a36348c90098955991f119ddad32c5b928e8db4deb02",
|
||||
@@ -4909,7 +4923,361 @@
|
||||
"0xe3d68466d0747ab6245e5d8620eaae080a0f3c2aa34a56defe8adaef56d5474a",
|
||||
"0x8d0f53bb5f7610133f04a763263815e092e43b0016369866e959d22eca466d85",
|
||||
"0x8c8f0fff76977593112a64826f15ec0e909d9a1f1589e121a37f73d881e6b696",
|
||||
"0x9ab1411e7ef5b295ab1a9dfe4ee1cd1a740af5b7e4b0a0e9c4a5f37e803c7c94"
|
||||
"0x9ab1411e7ef5b295ab1a9dfe4ee1cd1a740af5b7e4b0a0e9c4a5f37e803c7c94",
|
||||
"0x7a842e2c606aba52515ed7f114116bc782810bdade34b582077c57844e6af18d",
|
||||
"0x40b14c755b9cecf8264622d80dcb5864241c0f41e9665908ef3683e83d33e9f1",
|
||||
"0xd0faf39bcb44f583ded1cffebc93a8acb49a10b3bb2b0c9ed794b8aa4bd9e30c",
|
||||
"0xe1eb93e1abdc400b49eda22b5818fcf61c56309f10d5e3cf3794bcd7760c4c0c",
|
||||
"0xededdd50db9028797406a8559fd824a3e024b2362bb24f708c4f8423c657b31a",
|
||||
"0x20f6ed1b586555773ded5606e711a4b9bc47b84f45bdb97653de8eb4c9aa40b7",
|
||||
"0x77ade166b067475ddc450b0d6991b5a8de93c3b60d76d2b6a3f15ace449ea6d7",
|
||||
"0x766c057ee18d96d84ac85caff6e0ff4954d3add40ed9488987ec5f4865f06ea3",
|
||||
"0xe5dc0692cb0da1b9778ac99fb26b01ee7da45da56996dc7e5191f28e60a83bba",
|
||||
"0xb86ddaab167daf9b8d4827e12f19201cb7ba2fdc7767aa7054f478650360b5a0",
|
||||
"0x570f60bd9224065c7ac611e89e9737354b3186440dd328efa7ee0078850fc296",
|
||||
"0x0438822dca67b58f7c5ede70758f24ad164e1c0e3f6628274535101c13121201",
|
||||
"0x709382d302a6e5b21823af6ed14f22dfa79d7632b8649c67cff749fd9cad1d54",
|
||||
"0xd42c07bf201d8025e9202ce752e25207cae1804877149a756536348853478dfb",
|
||||
"0x82944c59acd3d43c731cc820a38f4b9ea4fafb3c5a5cc474ca0612c2e50f88a1",
|
||||
"0xe9c2665ac57f450a47b8f5407dbfa7575ef4fd3bc4c90a1e64e7e0f597c6c4f2",
|
||||
"0x862decca6c5c15a52cfc88a629237dc1740d533dea40a0850d8d0cff47672c43",
|
||||
"0xeb453cbb85db88ed6ab19e57fc0b90c045c3c0dd6aca67f3be579c6e75e6a1ab",
|
||||
"0x8f32d04dacbfaf1bdcde08205fe539f24a5e453c686257d5e39217ecf17e2a01",
|
||||
"0x81f1d7ed305f8981fd6ef9adc7374a3bab51b9f5d042c35e7cb16c7eadaf37ed",
|
||||
"0x8301660b9f830042d66b7197ca95eda84e9220d74f48ccef41aabcd8bec18c57",
|
||||
"0x07c00b7b9e698074ac994f5a96cfbfbc6f3e8ba34bdd727deb60aa3ab9f0f1ff",
|
||||
"0x44c59c12a76078144f62fc9646f8a37ac38a0db2db3cb002712834c0bf2a1bbe",
|
||||
"0xb3abeacf4280e9fa9357fcdd9b4e866938c37513e0f8a31b9f8c5733c48498f5",
|
||||
"0x72dd15a76cc64e9091fca937497027b77517334012d71b47502ec28f4cf31433",
|
||||
"0x0f86404545ab226dda8789da56d1d67edaf201062dc4f3268e0a4c3314ca6628",
|
||||
"0xf2c60e7441c1cd8b448b9d93fcc7e5f5a107d3b502454fb2f6b8607c49e12a01",
|
||||
"0xc272b28ebdd6cb2cc76cc255f68602e731579bc79ee8c9f6a3471474f14febcf",
|
||||
"0xed87c1f9b73e4f757d822e5161c6299aee52be1465ca389f0ce008eab6f51c17",
|
||||
"0xcec988f7b79b0b5b9f4b1e43466b56dcae86823e45997fe208e7f2cbe4604947",
|
||||
"0x0583ed42e92bf0cc3a54a4b80edde80606aa9a16d6254fe89b809faa0c7c5f46",
|
||||
"0xc61e76957a49acc14fe008c525de69838370fdb7c3063bc04dd98b031b12eb92",
|
||||
"0x5495eb0d9ac61871a364a5bd697628f4e480b8eea4c454cb583b0b11e59373ce",
|
||||
"0x3ee00540b8bc71257573acbf77c97969e0af184589df1decccc5490858b1399b",
|
||||
"0x6c10a21b5e7a430ed342bf38a88522919f217fb7a087576d7040f71b7d6a8e0f",
|
||||
"0xc0410a1981bbae319921e5af78c1e80e4539e1ba9140adb9139ff40816255910",
|
||||
"0x300f10eb6ba9d4ebd662710a91bfccde83a561b0dad7e14256a7b62e8b720662",
|
||||
"0x9f5de17b88d3bbc6efbab33a7b2d8f2c120643b3844f8e37d19e10f1526195f8",
|
||||
"0x2918baee5948882cfbbb57f6ba18a0434d2a0c3928eaea3d1b12de0054c00b5f",
|
||||
"0xf5cb3b2a6d29bf9a0988877cbe22a01726883159a787a324bf1e685b92ab8018",
|
||||
"0x08a9570f38daac2ca30d32e582f9f8f3a80e82020668b5020b29bf0456779b9a",
|
||||
"0xf807d91faee554d99a4a728b219d285834f231129a6225a5a4340bd74693b133",
|
||||
"0x7798ef990ab47b908f703dccfcc0d5507dcb7afaa9e5b98841825f7d2ac6b655",
|
||||
"0xe5d3b714c47a7f5b8bc95dacec03facff800774c72f4379051a1c574b919bfee",
|
||||
"0x5c5f6fdd4dc6d353865ee1edd5893b634f7239b327840b4973509027c8622f74",
|
||||
"0xf713adae992084b0593ac33894fea127fd73a6439533cc94d07b89c50b071fc0",
|
||||
"0x548d8bfbc57c4773fa2918dd13efd1f55a68d4a86b526f4560abcf48665ed637",
|
||||
"0xf47bdfe91932a9b4e968e64ad23690b7c3421137b44030000ffdd78ac798b3bf",
|
||||
"0x4ec25256a43c957c1cef4be253a69fc771889ad563ae677fe3e5ea6936cd760e",
|
||||
"0x9b8a28041d701c32f976fada9ce9a73fcf5dad79587c9e02b5abd7a299d74292",
|
||||
"0xc7c6285cea2145104924ab507bbd5aef09403f61e90ad04e0fa8a67e2abb140e",
|
||||
"0x2e839dc3048ebe96490dacdf688b017f388288954704c9a99cdf25f9203fddce",
|
||||
"0x37e37dbf1f4cb8b825cd5b68ea18a80a0bcbed46cbdb54c5ebb136ba4e88ff95",
|
||||
"0xcdebce72ebb15b5fe081d0f3290cd8412c56e93269541af2461598fa2a05cd1e",
|
||||
"0x37716cf58953f21168a83613bfb13db775fc96175384aee35f76e82095d19716",
|
||||
"0x7f7ed8d8526f0586f08dcfba6a279689d0f7aebfb0b11e627c7cd0a31ea99256",
|
||||
"0x1066be85b9d156b32227a7b74cd23b330f3c80e62f8b671b1dd03d2fbaf038b5",
|
||||
"0x53b3ba2bf9f02a52c7caf9ef6b46df80d9fa1ab12437774b2f2d073e886dfd5b",
|
||||
"0xad963410b3f77f2399b7ab925c7ef5cff512534c2e12e7e3e9573152f197f28d",
|
||||
"0xa3b75316cb456a516d1e26ad8df52a0a2894f26ff3a2938f9e09cbd9354981d7",
|
||||
"0x522ee88e34308bbdff564080e665cde9b3b4ae4a61afe558e5609996c1b2f855",
|
||||
"0xd7d377a1ea94fdab72ce796d3e62cffa96b2b2226bbc9fcea51817414fc367a0",
|
||||
"0x2ad4691181f4947c25d521a9d593e25c5e67c0b6150b3d9e27515c7808223633",
|
||||
"0xf76442cc901ec7207c33840e6a029e3655d279394261b8e2fc350547f2fd4cd0",
|
||||
"0x39688b8d86b6cacfea5d71e7311b01e2009a939c6531eb8af8e88b1d1b7a04a9",
|
||||
"0xcc35ca75b97530d9c19199827d373210bc9624fa0ef572f7c3aaf2672918da58",
|
||||
"0x85a6af5bf38ef40d2be7a529f3f370f56f380406fb8c5165f5bdff75a182b2ec",
|
||||
"0x54296a0ca61a8a80d4ce9333c985983f953975f6bd7eb6beec593c149a3359cf",
|
||||
"0xaa1f116c6fad9512afa8329eb499f197c5716a53ee283f06c417f45d9ce2fcf8",
|
||||
"0xb9799045a8f20c5885649ec1a632eacd44a72b794dc7492469f8c1abff3edb24",
|
||||
"0xd86348fcec2db2efc3deafcc18ca121de0176b1e89698a3c5244f377792784e7",
|
||||
"0x7267a4a5e59e848f1c3c9e4c6f43e7aa128b73261adb296a89a7abccdfd16cd9",
|
||||
"0x817a39c73cf85997721cb067b4e00812ab7fcde3e4506e37e6514c8c4e87846f",
|
||||
"0xb8e7a1c1aa51637ee68590a2d5be7a8124fae067cb3b0ab3898f5c45fb275010",
|
||||
"0x43f77794f4bb485488cf082b416885292a7b254057e7a75e331f4641c1ea2839",
|
||||
"0x9bf3050d09ec32ddf7c40fb96ae136085587c3a4ef6cd413f73dd42615327218",
|
||||
"0x069923933c215e6c60c8285f0afb83de8d4d9911a2c6417178f5f149388af874",
|
||||
"0x01e1fb2dcd7bdf5e30e5569a677f39e9356d70ad5e7c30cbc8c73eec66bba5dc",
|
||||
"0x39fcb505c1365111a0837993dfdf527a716a441628f248aeda785b32e04eeac4",
|
||||
"0x7837393e026631af009ee2f61e1a39037f97f77f98690ce92fcdd934b80d3ddc",
|
||||
"0x7695c9c3257358c759fd8c9018b2834ff56c42abecebaae806a281c03b887aa6",
|
||||
"0x0446616edf3b74a68fbe0c22029b61d16b67c300022211e013572b90815b6050",
|
||||
"0x274d5faf73eac9078b9d9c870bf07103aa749b0273871fa8e166932e3c0c1556",
|
||||
"0x34fa06554a8bf6a2305d7ad293d1617f5295c046cd6de60689af2af9d44decc5",
|
||||
"0xb641c3b6baa2370b85fb8bbb8c054fd9e7d44425a095778e859915f5b3931006",
|
||||
"0xd4db8f0bebfa97e5ba93fe7aa444eb74782a98f03735720482b5080a4d3d980d",
|
||||
"0x4261a0741221a7bcfa4d8bd1d6e8a62fe47ded969cc2b1446a7a76da9a23e844",
|
||||
"0x6664826f16716dd01d707896f892a24b29aa9b78b2a162bfd01aade882314815",
|
||||
"0xd9cacec24e60731fffc19e6fe8bf0241499ca78c51f38f841f6c1d91cb4f686d",
|
||||
"0x57755fffef02b43c1be01eed12caee89bf5cb4ffa8b823aaed947083cde2d0ee",
|
||||
"0x5d9bfb52ffa30989655e77512a3f40db66c790311c9cfb10d161b62b7542e334",
|
||||
"0x302296acbdbd6737cdb060223f289ddd71516c8c42cc5128bdd545de6df02bb6",
|
||||
"0xee1c6c48a63232e8dba59646f8d50dd6eded16ab310f39548300249efeaf7b45",
|
||||
"0x60d151e272c9e6874c9c9bd90e8b241c0ec1e978b5b1db2d6632542f9b02488c",
|
||||
"0x71c8d8c3da03c317eb14b12b5d403581432b3f0cea447da99dde8b60c9dc9cb7",
|
||||
"0x9fd4de13da3b68bc5682debfae937d4ba4fb67f87cbc30677941ca53f5029945",
|
||||
"0x2fb70f11714902235b3ca78b281c8ec80aab89f77e3fc59136bfbba44a2c46e2",
|
||||
"0x30109aa2d8e89ef3669e4abb89870c77c5acf5a34bf273fd56b925d1a4fca03c",
|
||||
"0x8d5c57cfcf34f5cd277a7d51c5a2fd1405b26231646db44043e735b8aae78478",
|
||||
"0xaf961653148c2e6007d011e20d008c25a2c842f5dea15e2fefa76b3f324424ba",
|
||||
"0xb4cc2c774796dd0c44923ecb3904e8f0c64839d32b7afd0c7f87eb0ba5e52949",
|
||||
"0xf4c16b1aeaf622d35b4f897c5b9c96358af2fde5ede56d377132a6e57549565e",
|
||||
"0x15c2a9f6eddc424c3ff3f91ebe6ac55d98442923267c80f59023d18b9d29cd9c",
|
||||
"0x65abebec89e4a4d6e674a29f3e5ee304050da861a3a3c91ebe79a3a8aa159db5",
|
||||
"0x46030219478d3c508cdbfe4cf76ce3924942cfbeb9ec6ac9e83dd5414cc8714a",
|
||||
"0x4712aadd9407b29cdd5d3f0747374fea712eb3202fd2c13795268d498dd0843e",
|
||||
"0xdc5ed31d4a9c4fce3f91f75102feef6da9a190638bf1f090df64175b531b1cc1",
|
||||
"0x077992451f048591ea0bb7b46818c602b6fb1d535ddfab2dfbdaa6731745fb66",
|
||||
"0x889307e6b877b390b86024c2f48afa3df0c9b375512e38ef778dde91dc950f55",
|
||||
"0xc6127728eccce59452504b58e10c29ab854712f248d6c90b43360c2786f38647",
|
||||
"0x76516eefb0f149ab9fbf2dace9fbdd4d435e583b3bb19820f45801abbb8309c8",
|
||||
"0xa3771e4be252fc17bac8dd8cb9cce1168e531061b59be4fc9115838af2d3217e",
|
||||
"0x1a0218061cd1c34a080b3a70cbb0c9f66420816a21a2f18f67e5fca6ce62b3f7",
|
||||
"0x42751bae5dfa6d27b92cb15bf0c490d8184b97fb647563bbb4a7612f31369473",
|
||||
"0x03bf5030aed483c4d07ba6a5be51ff968ce869decc37fe264b98661bccc55668",
|
||||
"0xaf604a8c41a8a2fb37e317b2a565afa4e25c289a17b3e7030106849094d517ed",
|
||||
"0xdbf8ed6fc0f94eddd863c883c17c974dd91f679194d4cc74316092327eb6bb42",
|
||||
"0x27624ca6ec82b25f6bcaae3b0159c79803228ef5a5e4443498e39e7ca8280195",
|
||||
"0x19338a8eb7d6884c8e6614b408ff2e5d44ed84e208673910f10fed7f1bf95c37",
|
||||
"0xb612ba1448b74093a5be0f2ba8d330ca56647eaa2c84c3a1e3d2ef765f430126",
|
||||
"0x523a7f824cb76717e0985ea2cabb23de5751c67ea03d6b569c30552d8bc9caf2",
|
||||
"0xdc4f2e1b704ed39f818c36b26df95184c39927246f52a74772be1eebbddc78a7",
|
||||
"0x4b5e3bc7c2e4f098b829f59ed096527216ea84bf9041d2a3c53c00cb7b5e7a56",
|
||||
"0x3cec3a6e9f95bb0e2a63194ac6353ac6fe9a12fad00e8f603703454638e8d819",
|
||||
"0x29b860f98a7239c9fe3994b68019ae8fd4d4009c07a088d23cd70ae6033fc727",
|
||||
"0xa8d1900bc2c3156c6bc8a41378c0d2c646f0328d4f8b8963f52ac0dd506731ed",
|
||||
"0xd9f8c709f2a6cbcda62ceae4c5244554af106e7f7fa0837d8887e23887d32e31",
|
||||
"0xea7c17fa8dbc43b3680741957d5a020cf0df2d491aebd6955bf6027a63f75dd9",
|
||||
"0xf764705990e0a12e1a97ea2cfe3d5fc0c28a601d1bb6c1bca0d24e61175d7403",
|
||||
"0xbd5d6454bb6824df5a458fbd1a29476e76c645564c42064eb6cad79237e17a99",
|
||||
"0x39e99ee5f716670380fcba0312b8b9d902dc3fe4e49e19bceaa4b2f3c2041366",
|
||||
"0xbdb6860183ab7aa4362223c519791e7a0b63379b87ef4c30739e57515aae764e",
|
||||
"0xbf6e060baab8b162bdf78e1996e30cdf4d6dd60b5daef909a5e7fada00090928",
|
||||
"0x1ddc651ab0d26eda2c160911e4be92c8ef843ef510ee28f1d0b8356760c595f3",
|
||||
"0xdfc38ad4e3225dcdd2dcadf32b024f754236601cb60c7aaec61a692a9f367acf",
|
||||
"0x326cd0b07c68ed36049ef9ce9af1db0593a26193d9988d21d8ab05f7ffd91adf",
|
||||
"0xfd76ef987cf758c89c04a221c10e50794132d3866bbf4e739e288a9b3014a9e8",
|
||||
"0x590f03df3ea2123eac0957d2a84a4a0e0184be0eb75851643c0b876f364942cc",
|
||||
"0x0fc92d4be9d7f7d5c49f3552d89203090fb7f4a4d34ac1a9925036c84d5d0d97",
|
||||
"0xd90702e78e72b71a3f7db3510c25d0b26d098da80003cfa4abe3c525e3212d2b",
|
||||
"0xec682fda87e3e66fc89855bd1ec01a80b515d6dda5f4b2d207cc5b2ac840532d",
|
||||
"0xa75c0c5ae9cc31a14badd2f0cd66b9c081aa541e4f862ef0ee5aa8a692baa89c",
|
||||
"0x9c237fd14d83ea449bc37922861be5fe81531264bb802d6a07c149b6883c826f",
|
||||
"0xab2240195acb14c2cb5f3e6bdd352c4c36765ba6d2d3042bf15b3942b50471d7",
|
||||
"0xe56052f2729f3d7d08b7958c0630b9c3ca2c6fcd9fd5655314bd1d5ca94e7852",
|
||||
"0xd774822e8bd746a6b253e9c71f80fa6d6f9ad95bdffad3310eecb98785c549d6",
|
||||
"0x4e478c8d5034a0e51e1e760fe258afc0c1f56cfa145f89bf34156426ea837b0e",
|
||||
"0xf84cba0083c61307c45e7caa3844053ca78e2a1ce181edf17041130f314f4d00",
|
||||
"0x24db4dc31929f9c0521a63d1b6ffd14939130c7d25df7a0827513a6ff0b28159",
|
||||
"0x969f5efaeff2db44bcebbe23b9ff916a15087a313e814dd9f8140388fa62a48d",
|
||||
"0xbdf6deadf158fbbe80670ae75744a419b999b747cc0804ec2a81b9082b5a4ccb",
|
||||
"0xd25da9760de21e6483493f5f781cf526527aa0bc17ee9c9abefebda4e8bc5b71",
|
||||
"0x83d5382a1a2132d7fa2bd48e06e59243f6ec71ee50626b65a84a7e5d3543f8f7",
|
||||
"0xa5720e9755e2d04563583af4a2581a8a1761e82eb769dc7695b1f9654e36f753",
|
||||
"0x97ceee5cb98a9e917223523650405aaa2e71cb12e568319baae1ee75df592fd8",
|
||||
"0x1e1e8d3d81ae5be21cb8445833d9b8928b6c9a6b9217532b15ce0ba6cefa64e4",
|
||||
"0x1c3ca12af63f1121e93b5fb602ab8c8ab1773d07bab5a60e78cb8e70e190bd4d",
|
||||
"0xb343c9f8dbe3e65462838749865a748d4a5eeebe5b6622b56325e2e6680626ef",
|
||||
"0x04eda02f974da35a3f4308d6b6be16b602d9317256209bf674f3282b2bda878a",
|
||||
"0x0f85c864e5ac359d9a0ff54a4e0b44a31109c57d7c2171185138dee5638c627f",
|
||||
"0x476f9f649f2365455d4756f541e8b8f8e34b32f8c67196a06fff2f71abddf5e5",
|
||||
"0x185b523fa66564ed0e4cafadabe1c04a399b51114f5fb743136fcb2a0a53e477",
|
||||
"0xc87106d70447c962f367b567b37281e4d840fc16d7b97dd349ecd073d0419cc6",
|
||||
"0xc0e624f73d54230b99169c8919c965319ab2a93a31923bd22b50350bf0d25798",
|
||||
"0xd78f2ea276fce38b53569cc64a6ce7ccec2fdf4f1a295106a1f2c54330a0db40",
|
||||
"0x4a1c2807ccd57ecd989a2b0d4ed2d3ec609449e15c5652cff515ba5506cfb745",
|
||||
"0x453e4ded943f491b41f0522188e88b28667172202b8a015f113171c29de193b2",
|
||||
"0x9ea9a96b93c19a00f2238e15bb3c74409eca441e6d0ecb47b574fa8fe7390c67",
|
||||
"0x9833f04cfbab3190d2d831116f1f0e1871018d862cc2389511bc266756963540",
|
||||
"0x48ccbadc3d160d322bfc61d44962628b088da09d045c43d028b1b9fb979462bf",
|
||||
"0x33d90a0c09d27087c15b01228250cac34fd4307d45593e7239096bb77822f6cc",
|
||||
"0x545e2a8e511ef59a5fd7f183b0bed449d59788e4e377350b56bdb387e82ad4f8",
|
||||
"0xe7e31fa668cee51a20ad4f2bbd459016639bcd47421836cc1bb3e0e2a4705998",
|
||||
"0xaf6e1ffeaea0bcb61d5d90fb6d6146bf4f6102f49c3e5f653e1bcd6b043ab3ab",
|
||||
"0x98bee111ed4d2cbd72725011d5a565b1873c86b8f3e17f16389ee009dfe3c6e3",
|
||||
"0x2107b120a64b8fe21702af4bd26e8d981fec6d0051c83046bfa5dd05354ad05a",
|
||||
"0xc982a8ce403f43557d0a812b8be06827d88e2410f6e7920971972fb205bc8a4c",
|
||||
"0x5d58c764a39ccd3edc5e1b37f3ec73ddcfafde249e066c6185712c0d566b2e33",
|
||||
"0x9afff9b16248767858ce0520877d7f414764eae8ad77d9810d615540c119e476",
|
||||
"0x6154b7412dc1fabb80fd7ee43a3b91651e07b62d15afba8c004611d8ce2a88a9",
|
||||
"0xfa859b6679bd6a2b283ad4ba43b8b3d96b19292d017e933cb307100e0e2a9c36",
|
||||
"0xf32a85527d705fa439494f314800609a6c5f6657b205b0127b64cd595aa2c31c",
|
||||
"0x02d1fe3725fad05e13189d6d9e078af8c825bccb5775dd1a6c90be3b57081d02",
|
||||
"0xb003929860e22e0a4bebf5be75be8ac86a511e3f9e9b421aa9a99fe0fa4d9144",
|
||||
"0x583341c3a9526d29c43bf22619df050676fc5e56974a8588a91bfef7409818f4",
|
||||
"0xb94ebbab275786dbeff9189ca740bf324f916c76b800da87e6e507d546128ca9",
|
||||
"0x5f26114f75c4f839fd6776b3a67b1a74fe6afe5fee1d3053fc5b09b38a2f31f5",
|
||||
"0x053d6e94968bde9f906aa52065c0626810d138908f1645f2e563d3aca9660276",
|
||||
"0x458fdb60ca1d0b7ffd846744ee6fc7219ce6700b4e5cd97603c4885563a0d14b",
|
||||
"0xdc09316757c1ed63b9d984647db8fb69fc9e8e6153424a6e99016f868dea613c",
|
||||
"0x409e2e26caddccbabf10754bf500262fca5aeaf6ebc937062e1d59b087873a70",
|
||||
"0x288ee1a1e4b4437ac97c7130d4260bb0298ed2038b57c801fcf2389762a8dbe9",
|
||||
"0xb82f496c7c8c8d2847ea7434e15c61883f4510e3151f56636394d88e902e19de",
|
||||
"0x5fe701b2ac79e258c7201cadcf7892cd37e76bf9f7f9b9b46d39ba0fd359076c",
|
||||
"0x32a841cf4e27eb60b5a6825665cc257fd1db222d501b42b5c6a814cdcddc1038",
|
||||
"0x5b76c42acd108597e0f0ea8c92acb039a047dccc7f294205d1e404981bcffe0c",
|
||||
"0x7084da3532f91d33a42701d9c580905f4cbc4137f33db33a579aec2ce5db1c53",
|
||||
"0x11e58ad87c481e2d1b1583bed5b6e71ffbc1114bed29b7ac14a75d852a4741b2",
|
||||
"0xdbbe146f3e58fa32d465a175205d757f18929cea4870bccbaa2698c58cd32f6c",
|
||||
"0xf1dacbb951e0663d5db612046e090c04f18bbe31271d3d786f20deffd44b4205",
|
||||
"0xa11dd2266cbe0af5b7f1f7955c28fc43a88abb8d82ac18e835723c85e8fd2d22",
|
||||
"0x716ed679abca531ed520deed7b6d955e1c07c5ea483cb57a2322ed8c7a5a31e1",
|
||||
"0xca4e5b466b978777d7a60a8bd841271da8643bdf0085379677131bf4b3604f33",
|
||||
"0xe3ab5b13f5cb1bd8dc38c5182a7f16c02abdcae7a310d6c0233b96070d9d30f7",
|
||||
"0x5f29236e49036d429f283d25a2e4cd6ee8f01b314201a34713b50871ac1ab628",
|
||||
"0xf1e41d548090c62f207208b575e0bb7b4eb08c30abe40525effbcbb8b5511482",
|
||||
"0x088fcad31ede2ffe1cb9e67becae368ba3be97a02d4837be59bef650f4b90e4c",
|
||||
"0x4f4cadc003d445a2014dd5f819a2b67e67620a21af8302469f9ec264cee75e2a",
|
||||
"0x23b331796e1c5c95a701a1f791ca392da953a7a9d5d2a834d0cc941ef6567250",
|
||||
"0xb147414487aa60ae8ef7aef8577ce50b4a750b0ab77175aaa39fe78ca5d2e12c",
|
||||
"0xa2250e2b126ef24cb732c79cf87afc5186b88402b70e0c9b7d3139205c7dfd09",
|
||||
"0x5c40cffeb999c74452e77145e22c3c1d1080deadf4f49e40cd5184c683f628d8",
|
||||
"0xe2f8ad15a61579535dc9afc59d9ad16308b80e409fed46af55b7938856485c33",
|
||||
"0xec81eb466fd503be4a807bad9b2d0b6ccc24d1dce3f82f69adc99dc81d69a3b5",
|
||||
"0xb87d20dbc44c1a473048e96a2957a4b9fb2ea606cf7b3de9d44937d18695f0d9",
|
||||
"0xbf0dd81b0e07b07b22deb6b97d5cbd1d03a2726a1e7bf9f795c8104d1ff1c458",
|
||||
"0x6aeed28f1590a1c96f1085a1867a4957673cbb8e4251e5876a43182e7b40e4ec",
|
||||
"0x24df74cf385560d990f59f8c59d3545662f71b42736bbd1c1361b5a1c45d2b47",
|
||||
"0x881647b453a1e3ff0b6e64a3667db62add41599f003f9032418576323a5ce1f2",
|
||||
"0x9fb9c9bdcfcf35e02f0029f74b86d131be7cb49f409055cc075008e9ae33bff5",
|
||||
"0x5f17c4c7b4d1b0cfd3929eadb46bf1060b8394f6bd5c0095623f73de5f8acf03",
|
||||
"0x63c4b4aa80474a3cf70243f3a2d891266760f6f54693f4f189c0aa9b3d6302ec",
|
||||
"0x97921aed12f6d78f6052050f7401caca6bd07cd643fd7a30f681a72a45b64a0c",
|
||||
"0x82e6c73da95617192ccbc9374bbdec4c4323f8f63a27197cdb52a0d73b88e16d",
|
||||
"0x3e24fcbe6a8d8ba769994150cc7a17dbb38d2248af14bc8328f729f4e01fe173",
|
||||
"0x8390ef908e1dd84308347bdecd7f7e1f176551e291c6b8851c1f90d0ee4d87a3",
|
||||
"0x016143668addb39c55a8c5397cf097567faeec1787643a89f8feaf817ea10d5b",
|
||||
"0xde78935eace5f67e88d141d650c35b2b0c5144b12833a3c4bb64441aca1afc23",
|
||||
"0x129345fd67f04b97d9e76fc9758c80b0616a68710f51decc61f85fed9250396a",
|
||||
"0xcf6625191fe20056831cfa3839cd3f8fe60d17e6e4248dc46ecd35401986770a",
|
||||
"0xda56c24559455221d6e465dc3385bb8fe8b547f96952e07647e46e10127873fb",
|
||||
"0x85045ce82b529f7055bb8496f4084283edc86b6b79f0f1fa060ed9050419c542",
|
||||
"0x4b94dbf2a96a4749a04d47fe563644b7f396f4c81753d8ec3a70e5065df0a3b9",
|
||||
"0x4b025b46575b54136db392c9075b5973a421fb521ab37d8760a04f90b4f8526b",
|
||||
"0xcfdf125601a1939cca129c4d38dc89a6157cf0a51400bfd8cbc1ea9a3ac5e859",
|
||||
"0xbb9b417a9d9c975a1707778fa83950a2a6f6c7c20620e623e913509cc256c26c",
|
||||
"0xc2dc9b5d9413508462391fbac33d1d4ac2fc4b3167d152d0888c5ef9b18a9bf8",
|
||||
"0x918d35dede6db7175e5a11d9c26ed38fe8198da231d3955b1eee020ad32fa3d3",
|
||||
"0x12515f32629d7e71e2f1ef0de1a08ab2ed2cf9cb2ffea11aeab06e7dab64eec8",
|
||||
"0x3484f89e98c0436f603319b8c5d5e324f3e2cb6995be3334641e14a21e998b21",
|
||||
"0xb045c079ca13a4a6760bae38dccad8b35503437c4643b1180f99b2bef15b9eff",
|
||||
"0xf81cb06b474d642ef15ae0382f3d792071862d4a00a967ed352fcf5fc55529b0",
|
||||
"0x2edc394894bdc21c9827c789cd1f1226459e5489f7a87dd941efdcee56d0be78",
|
||||
"0x7a1993168a29b0869fbb337144031dd0bc47520ab9498c9065b71fc90a100294",
|
||||
"0x1963f11d488f5db4ea7f6e99b0bfe5006702e911930a7a95fab8a45ea1c4c955",
|
||||
"0x7e12d33b54970a2fba8539d57c02b8318fab2f22ceb8b0ef69b6cc9ccfbd0658",
|
||||
"0x32655b99bb59604c91af6270b15834688de512ca3088544785c0f0304d1faa20",
|
||||
"0xec8984da3bc415604c9facb5cec0238f162b3da22fc4d20bcfed387c647728fe",
|
||||
"0x7ba1756f8fa6637d8cb6cc588a679f6366827bc2044865744837c63e8a5aadcc",
|
||||
"0xfc1a94a88f1e52bb78a0862eea4b996444f0264a3b301c1a31e59744d0216de8",
|
||||
"0x79472bc4de84a0c430f15bcf8569486cddd2de985409ceb8e48abec8aa3e3fe7",
|
||||
"0x02bc578dcc715304c651a43d8dcb4a761d2073a93cca2c39da3ee513f0c6d415",
|
||||
"0xcf6175cfa60c20178241c18111d64f8837ec008751c5c333bee96c616d3cb6d1",
|
||||
"0xd8281202c7b6da2a2541cd7f8d4270066f6546bec601e83647896ebdf0f2eb66",
|
||||
"0xc4975ca8b2b71f61d2ba2825833df91096bd733301d54a3c7b6eca016ac14153",
|
||||
"0xd01d6f14e93c8ba17a602378bce1c9bdb51373675109d6233c497b6c638a03a0",
|
||||
"0x805057e19b7dd857ec014b4e6333bb60f48c02d29b128fe37a69f952df8ef16b",
|
||||
"0x69c55bdbaf74bfa3d53ed32b79dd35ac2c24dd723a1c0bfd70871cefa4dbb8a8",
|
||||
"0x523efe8059e6e8e2abd85d77d22123f97cbbd9864b4a3ac1fe0c0e4b8a7131eb",
|
||||
"0xe5a4f129016bcfbd71913d1eff01cec924f9d130b8762c921d43fe5bbbbdbbd0",
|
||||
"0x07f68773d16907348ac6e7c5be293ee1163ef41b91a2a8abb17a004c4796fb42",
|
||||
"0x90742f88c71f9e689b6d2ca0236c48bba0e8ddeace5fa4d53a5af082055cfd73",
|
||||
"0xaf7af6e9f695c4ca9e9a3c0229d94cbf02fcafbc4ed978a6b662862182308a72",
|
||||
"0x0208eac99df5025cab13d9767a2ba3e42ba1eccb72cfa01d87e834d15eea3751",
|
||||
"0xee9ff9384cef76b51a9d5b8eb12fd7e00ee7f8142f81bd68393e7fcf0eaef90a",
|
||||
"0x4770986e657683d901d73df444836f11f169f94ac55ec81e4e19f2212052788c",
|
||||
"0x9f9c16d009da6e8ee20d9d5f3bd7f1a77b853dfd19beef68d980fca6bce2b707",
|
||||
"0x468efd7c8dad29cfff0e278fd950f89e2d5a57d6824c6c1a7a7659bd7e7c0ffe",
|
||||
"0xd0391bd0a2c1fb2260d89bd5e519d4ef26b4945a7ad0c1b695687fe1b24698dd",
|
||||
"0xdef9ee668e09f8769b2c706a8de426e06f0bd9c264e67bf0c0bb177b851cef23",
|
||||
"0x10c5b79048e611c6e65f92dd54754753e595cd8f8f0f1005d7a647fa59deeb78",
|
||||
"0x4ce6d5812d2565237a9b018ed6ec386cf3e9fe1f2f429605288f2ef744c5a940",
|
||||
"0xbbacf6662d816d5eb14fc1271c1a3404de94e12c175545bc8273c231c280b789",
|
||||
"0xb216fd154d3726f16907ae571728d92ae2199872f180e4cd6be3b53a8dd43ae0",
|
||||
"0x2b76e6685604c69f29399451c66ce053ae033ab011eb52c97c112df968e37232",
|
||||
"0xf93b8076ce0dc6742196d2c9af501fad39f570cd927e8fe3b8dac4127a20a6a4",
|
||||
"0x35027cc654f998af75b8379fac0a9d51703f058b518880e25e658151619f1611",
|
||||
"0x3e7f59319228d40e5e07c06b696ad6478237ed0c8a71cff418ac259c6b5579e4",
|
||||
"0x7295e21fccabab1545c1e64a57f0401e62689057ab4fef26f70c8d02b63867ab",
|
||||
"0xb06bcf07fe1345c41ba16df213d699e2e185ef2fd3b5e19b194459d0b7baffc1",
|
||||
"0x1b13d005a29e35fff33373e2d8abc81805a85e7970b48dca8fd605069c8a0d85",
|
||||
"0x90a5a61ce554bb73253d7f62c78b1764f03fb0fd8f65b6aae4f9e529acb1d991",
|
||||
"0x1b1eccf7565339748947358caf473ba0cea743da2ed4790763d3ac8c402f261c",
|
||||
"0xef9b05ae7ce93febce342336e40922e0884891da43aac06f3e9bbfc0aec688f9",
|
||||
"0x11e1075b50de92e960d0d65e9b37b3cec81095f5afc2afccc6a9a8a325264049",
|
||||
"0x128e6dba4205701f673dda9e980dc0c02f3c0c8cbc570f9a240257a261f81b39",
|
||||
"0x6fd9d3eaffaeebd52ce93ac8fcd0f69b146e2c0b05218850de1c9218db8ecd8f",
|
||||
"0xc47e3487ad63b7db773f413cd5302818061f168409c27ff2daba4579c0a4263f",
|
||||
"0x0a55695d4a132063735f7319d3a90a2e0b83fd6ec6b6f9994068f928f68afe12",
|
||||
"0x39403d84aa319edbb18e0313a61ae075ba9c5dae40b9850eccbfc3e09e6b27a7",
|
||||
"0x79ba98eede4cd0b7031472baacab20df85c704a26e4cfaa6e01e3d4a9d26ca39",
|
||||
"0x219240759d36a317f269e4301256164cb3709628e0ba07e90a6bedd664cea059",
|
||||
"0xec793562f8498937f270c6ae5490ab8f2ad21a20510699dc4d7d4d0139efeb3b",
|
||||
"0x0a3e9c209903b906013c8876cb4292e6ccc8b76dbf4af2ca25d8260f9f8e7c22",
|
||||
"0x0eb347bb16d897b4909dcaf31a0009e198cd197f722075c112fe29bc9f017f20",
|
||||
"0xac1e6a97c51f5051dc8f3a1fa33c1071e29aff3d7040972dbb5481ba215010b3",
|
||||
"0x7e1be83ac51c7e68110c6984da43885af18bc9fe988a57ada7b2379d0a122563",
|
||||
"0xdb01b1cb4084a43c9a57bf8a65a58245edee5bbbdcf0573a3626e9290b4a2e6a",
|
||||
"0x6c97523c89da4c9325fe17d2e879bbd6b4693f3e6d807564de83ccf801e66737",
|
||||
"0x7511c0b30bd4dfa6f9a4f38793ee11e2a616de5d9d2212024c0875052ef2559e",
|
||||
"0x6faa338fd78b41f2ecb623d578520b373e0c74caafce95938161dbd95edb0e24",
|
||||
"0x0622bf3e00fae0e244d138f73d16035cd05aa9e0c4c16d20b36adad77951c2d4",
|
||||
"0x72e1ed876e0bcdbdd200dbd55a9d7e8248a4c7ca75588681b61f6f76eb980060",
|
||||
"0x981a052ee33c36c52fc33598c2563ff3698e1efd130090658cb457bb814ecff8",
|
||||
"0x2b732d67211042b340c1bc49682518bb00dfcaebd0cfe861b5d38df9c127ed64",
|
||||
"0xfcba6702d24950030403f872be646d058039d735cf297fcedb5daa255d47ce72",
|
||||
"0xba3bdc1bd47ab43c2d39ee67a512f306e987b577166d7037705a1fda772bbeec",
|
||||
"0xa39705f9efc0c0b9051742b705dab9fed7a08b3a00ff15583e15de95a9933356",
|
||||
"0x551658242a3237fda7b61eae6dc40f368ffbbe3e7f292bf1b3d291d1f21a631d",
|
||||
"0x631783a116fb5af727d2617276bf310e9f018e1f072d9f3d5432773ec29a193a",
|
||||
"0x7d2bee7cbf5aa7a5247f047b1147f55380e035a5ff1ce958037d96a539fada37",
|
||||
"0xfbe38f5210d9fc7c3474be4ff932d1ca393a565426f5d1443537e962beabbbca",
|
||||
"0xfc9b71f941a0a9dafd6356c4a42c369f22144b43f32f5d50fe3d4c1cf3ee3cda",
|
||||
"0xa4eb11bb0a0e210af085dc446766f4bb0d19dfec04e9d5d0d2c0ee390597906d",
|
||||
"0x42e8e9e3d4d6de275146369fa7c010a10979793276a4406bbfd77a543809e762",
|
||||
"0xb2fef38ac3b58b498cdad7d195bdb3604ca0cfc0ca3c7282163636d3022def43",
|
||||
"0x923269e9a526ddaa446a2e7acaea5189726ff77e664c20a341f6ad2f6b810d5f",
|
||||
"0x02e876ba6df7c9ddd7a9ad9bbc15f5918b096e299260fc85a8c7ebaa71d7dde5",
|
||||
"0x660442f393884c6c4b879168ab3c80c57318c6c62a67ba8df3788edf9ad7303f",
|
||||
"0x37f7ab248fded056ae5ecde87bf51c1f4baea786fc7c9f5b6760ad13c90659ac",
|
||||
"0x36fda244e2896e45d3a8a9ed67d7c09a2974c75944a7233f571928a497b55f8c",
|
||||
"0x4914478536196c3c813fe151cdf37097c6dc9e8d5c0cf9b370fe7567905fc4be",
|
||||
"0xcedb88613a1d6fbc24909963911efbc5ff56ba09377350b5e824123b50d1a910",
|
||||
"0x236fe31e63e426111507b2f972547255bd12c6f5df9079953a8b8346179bba57",
|
||||
"0x2f08e1b0ad4024814428237b4f0e7ca5a83257d25a1cb97f42db14307113916f",
|
||||
"0x41e45a3a2239551e8cb9598fb855f3d8922386c2e004426e294d111a94856b92",
|
||||
"0xd5d385b54446abfa8c78950aacae52edede3a7a65d9c7515043431a4498e4f85",
|
||||
"0xf2d2eb5169760d81d16067b9453979783a2feea91dfa253baa3183f2419478b0",
|
||||
"0xa5aac8d064c4f4cdfdd2c7f7326c1e0260aeb44be48b391616eb01fc6d30c95e",
|
||||
"0xb2a298085b0a082fc1781aad1abd263e9cc2c5eeeaa70acd88e8bdfbc0be7d15",
|
||||
"0xe2d19c438ddb9b96e77a9bc70566f49021bb6444569eea3cd039ecab4d61f73a",
|
||||
"0xa8549fc117d3faba2ca53efb94bbb37e9cb82bed8273e408da5ed47f5df7aab4",
|
||||
"0x161c898240dd6e0a0a1f1f5948c652a796bb6586995783a35e7ed6c3c02fb82b",
|
||||
"0x57214b17853934f1a548a7e9942849a04b9220f5b783a9d2be7395108bdc12e7",
|
||||
"0x7902ef6c69f5d0a3de1e45d8b46aebcf35aa87cc5f4644186f1c34614a429175",
|
||||
"0xc290a119f495ff04f406c28461e2de50abf92743b7fdd680048e491044fc59b7",
|
||||
"0x09bf0fa4aa8b65dcc8f937e46287eb2585c85c587b425f8a0af69d02948f35d9",
|
||||
"0xff20130699483dee0caacca392c2ad58738f61ea2443869616a3bf006e0cd1ad",
|
||||
"0x937c629f7307f7411a4b1cc5b92f6a1f1f42f716463f15c449c681d16525996f",
|
||||
"0x7cd028f48f117d8da3d537f0bb0fb0c832d3111d16fc116bd06454ddd513a095",
|
||||
"0x4bf15bb783cf917375b5494e00ce003d8da01c65fcbac40d44e62a6172f2cca8",
|
||||
"0xaff5ceacf024e9146631c772e4e87f223a241e789c88ae083da716c9aa47b860",
|
||||
"0x68c1db9a727678d2018ec98d0bbc369faec2fb1283b479abd5d6f2b1b04036aa",
|
||||
"0xe70962a032b4cb81910cea9911eef50ede2eeaa6f487f1e9f8fbf88f133249b1",
|
||||
"0x1bc2bd4440a1412fbf582d167e0d08629ad2bfe0bc0dfaeb5eb7730a4baf007c",
|
||||
"0x2d4cbafea30b01e466b41f6911deae979f4f5c82dcbdd76f711f7bf9300c23f4",
|
||||
"0x252e39a51862ebaf28d9b38f9fb842c70b5bf0669ca008b4c83c542e5236a1af",
|
||||
"0xba04c89c7ec2867d778f8632e7f51e11f06e56004520444ca922eabdab623473",
|
||||
"0x74b8dc3bf589a6d9051fbed9af3021e8fb775eab0f457cfd5d38b2ec8f88a24c",
|
||||
"0x8c0a98cd1665f50b702b44e10dfbfaa70f08b65ede72e39306b1d31b75c07afb",
|
||||
"0xa38c3526f5f6bce7e64a195cf8659160bc7318b8862ba206535626c338485c64",
|
||||
"0x4ad34e3c6be8cac9be3fba22eb7e99d951baf5827df5ef921f2b01d63862e116",
|
||||
"0x596670c729beb030c8756bf2ec6c884f9b4edc433a94f5dc5d4d337dbb712d76",
|
||||
"0x39611d27f11938df810165987ee7edbe87cfb7e4068216cbb45848b4029f8419"
|
||||
]
|
||||
},
|
||||
"accounts": {
|
||||
@@ -5013,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",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -34,7 +34,10 @@
|
||||
"eip140Transition": "0x0",
|
||||
"eip211Transition": "0x0",
|
||||
"eip214Transition": "0x0",
|
||||
"eip658Transition": "0x0"
|
||||
"eip658Transition": "0x0",
|
||||
"eip145Transition": 8582254,
|
||||
"eip1014Transition": 8582254,
|
||||
"eip1052Transition": 8582254
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
|
||||
903
ethcore/res/ethereum/rinkeby.json
Normal file
903
ethcore/res/ethereum/rinkeby.json
Normal file
@@ -0,0 +1,903 @@
|
||||
{
|
||||
"name": "Rinkeby",
|
||||
"dataDir": "rinkeby",
|
||||
"engine": {
|
||||
"clique": {
|
||||
"params": {
|
||||
"period": 15,
|
||||
"epoch": 30000
|
||||
}
|
||||
}
|
||||
},
|
||||
"params": {
|
||||
"accountStartNonce": "0x0",
|
||||
"chainID": "0x4",
|
||||
"eip140Transition": "0xfcc25",
|
||||
"eip145Transition": "0x37db77",
|
||||
"eip150Transition": "0x2",
|
||||
"eip155Transition": "0x3",
|
||||
"eip160Transition": "0x0",
|
||||
"eip161abcTransition": "0x0",
|
||||
"eip161dTransition": "0x0",
|
||||
"eip211Transition": "0xfcc25",
|
||||
"eip214Transition": "0xfcc25",
|
||||
"eip658Transition": "0xfcc25",
|
||||
"eip1014Transition": "0x37db77",
|
||||
"eip1052Transition": "0x37db77",
|
||||
"eip1283Transition": "0x37db77",
|
||||
"eip1283DisableTransition": "0x41efd2",
|
||||
"gasLimitBoundDivisor": "0x400",
|
||||
"maxCodeSize": "0x6000",
|
||||
"maxCodeSizeTransition": "0x0",
|
||||
"maximumExtraDataSize": "0xffff",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID": "0x4"
|
||||
},
|
||||
"genesis": {
|
||||
"author": "0x0000000000000000000000000000000000000000",
|
||||
"difficulty": "0x1",
|
||||
"extraData": "0x52657370656374206d7920617574686f7269746168207e452e436172746d616e42eb768f2244c8811c63729a21a3569731535f067ffc57839b00206d1ad20c69a1981b489f772031b279182d99e65703f0076e4812653aab85fca0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"gasLimit": "0x47b760",
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"seal": {
|
||||
"ethereum": {
|
||||
"nonce": "0x0000000000000000",
|
||||
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
},
|
||||
"timestamp": "0x58ee40ba"
|
||||
},
|
||||
"nodes": [
|
||||
"enode://a24ac7c5484ef4ed0c5eb2d36620ba4e4aa13b8c84684e1b4aab0cebea2ae45cb4d375b77eab56516d34bfbd3c1a833fc51296ff084b770b94fb9028c4d25ccf@52.169.42.101:30303",
|
||||
"enode://343149e4feefa15d882d9fe4ac7d88f885bd05ebb735e547f12e12080a9fa07c8014ca6fd7f373123488102fe5e34111f8509cf0b7de3f5b44339c9f25e87cb8@52.3.158.184:30303",
|
||||
"enode://b6b28890b006743680c52e64e0d16db57f28124885595fa03a562be1d2bf0f3a1da297d56b13da25fb992888fd556d4c1a27b1f39d531bde7de1921c90061cc6@159.89.28.211:30303"
|
||||
],
|
||||
"accounts": {
|
||||
"0x0000000000000000000000000000000000000000": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000001": {
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "ecrecover",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 3000,
|
||||
"word": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000002": {
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "sha256",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 60,
|
||||
"word": 12
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000003": {
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "ripemd160",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 600,
|
||||
"word": 120
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000004": {
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "identity",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 15,
|
||||
"word": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000005": {
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "modexp",
|
||||
"activate_at": "0xfcc25",
|
||||
"pricing": {
|
||||
"modexp": {
|
||||
"divisor": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000006": {
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "alt_bn128_add",
|
||||
"activate_at": "0xfcc25",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 500,
|
||||
"word": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000007": {
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "alt_bn128_mul",
|
||||
"activate_at": "0xfcc25",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 40000,
|
||||
"word": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000008": {
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "alt_bn128_pairing",
|
||||
"activate_at": "0xfcc25",
|
||||
"pricing": {
|
||||
"alt_bn128_pairing": {
|
||||
"base": 100000,
|
||||
"pair": 80000
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000009": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000000a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000000b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000000c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000000d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000000e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000000f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000010": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000011": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000012": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000013": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000014": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000015": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000016": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000017": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000018": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000019": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000001a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000001b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000001c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000001d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000001e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000001f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000020": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000021": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000022": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000023": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000024": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000025": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000026": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000027": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000028": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000029": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000002a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000002b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000002c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000002d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000002e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000002f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000030": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000031": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000032": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000033": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000034": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000035": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000036": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000037": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000038": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000039": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000003a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000003b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000003c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000003d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000003e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000003f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000040": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000041": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000042": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000043": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000044": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000045": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000046": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000047": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000048": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000049": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000004a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000004b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000004c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000004d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000004e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000004f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000050": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000051": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000052": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000053": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000054": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000055": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000056": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000057": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000058": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000059": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000005a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000005b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000005c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000005d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000005e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000005f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000060": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000061": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000062": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000063": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000064": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000065": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000066": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000067": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000068": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000069": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000006a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000006b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000006c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000006d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000006e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000006f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000070": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000071": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000072": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000073": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000074": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000075": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000076": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000077": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000078": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000079": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000007a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000007b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000007c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000007d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000007e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000007f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000080": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000081": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000082": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000083": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000084": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000085": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000086": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000087": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000088": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000089": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000008a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000008b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000008c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000008d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000008e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000008f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000090": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000091": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000092": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000093": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000094": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000095": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000096": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000097": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000098": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000099": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000009a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000009b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000009c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000009d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000009e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x000000000000000000000000000000000000009f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000a9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000aa": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ab": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ac": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ad": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ae": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000af": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000b9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ba": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000bb": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000bc": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000bd": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000be": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000bf": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000c9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ca": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000cb": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000cc": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000cd": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ce": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000cf": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000d9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000da": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000db": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000dc": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000dd": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000de": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000df": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000e9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ea": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000eb": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ec": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ed": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ee": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ef": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000f9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000fa": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000fb": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000fc": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000fd": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000fe": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x00000000000000000000000000000000000000ff": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0x31b98d14007bdee637298086988a0bbd31184523": {
|
||||
"balance": "0x200000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,8 +62,8 @@
|
||||
"gasLimit": "0x1000000"
|
||||
},
|
||||
"hardcodedSync": {
|
||||
"header": "f90218a00379bed5cf7fb318965ec9b496aadc573fb78d1570ad2c43703c72e6c6ed997aa0b86c16b5c12556b0ea79b4d52ec77e3a3362ef43eeea51b594afc53c4b0ac115942450ec589db090d88e8de36c1790ca309841181da06183029c4e9e730abd17f5ea5427b626ed83796cab9bb4f28444cb7ab159f8f2a00ef00ef22f20f7d802cbede6ed8ff42d62671a7c07af9496e14710d7e63bbb9ea0a0e273f9d56a2ad827fb338fc0a109c28c0eee076d01454b76d42c99f8c54168b90100000c0002000000000000000000000400000000000000000000002000080000000008800010000000000000000000000002100000000000000000000020000000000000000000420000000008002000000000000000000000800001100000200004000000000000000000000008000000000000000000000000020010000000000000010000000010000040000000000000000020000000000000000028000018000000000000000000002000008000000800000000004000000000000000000000000002000009000000000810000000000040000000000000200100000000040000000000000000000200200000000000000000000000000000000000200000844af3d7d883486001837a120083146f76845c2c29239ad983010814846765746888676f312e31312e348664617277696ea071764589dfd7ecd322aee118da27aa747da4f5d14c1a5951f9b3a297d47a031888ba12cdb8daaeae57",
|
||||
"totalDifficulty": "17277173430188370",
|
||||
"header": "f9021aa0a8da98b6ef1e12b6c49e85b0e965f1ed1688f5e3605f06bb3c6ce4f857aa0bc6a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794635b4764d1939dfacd3a8014726159abc277becca0d03c319fe68a91e22fb3b945a8dfc73b817976e29cf57e6c8425e6a02e9bf034a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000849fe1546f8350d001837a121d80845c9d55f29fde8302020b8f5061726974792d457468657265756d86312e33322e30826c69a04bf72e97bcf64717bfd655e2bca9ed1a5253cce5373268729161b1786ca4710488db3c50627f9321c4",
|
||||
"totalDifficulty": "18787961645682286",
|
||||
"CHTs": [
|
||||
"0x614648fc0a459451850bdfe353a932b5ff824e1b568478394f78b3ed5427e37a",
|
||||
"0x1eae561c582dbb7f4e041998e084e165d0332c915d3a6da367638a8d24f3fafc",
|
||||
@@ -2380,7 +2380,277 @@
|
||||
"0x12cf00d3b11cbfaf2038ca1e9de63e4dff65a3352da5824043978ba8fe7e08cf",
|
||||
"0xd64011bda551b01b0b33e1065b0069fd1fe103e2e68c50fc5bdf1f99b4ab5e0f",
|
||||
"0x3e3bef8f3d76d1f410327cfd8f4453e0fb9ed392da173e26ffaaed662411f7af",
|
||||
"0x435816db536c536e0470a3fbfa32fcd6adab877831ffa66417e19bfaa2c9c62b"
|
||||
"0x435816db536c536e0470a3fbfa32fcd6adab877831ffa66417e19bfaa2c9c62b",
|
||||
"0x19d27119d0c702eb7735d70b30c26567d6ae4c5d204870a036f2273f027a80a9",
|
||||
"0xd48c41e8365e9872d953b89e2b3dd0fa762b3360958ec9928124f54c79df5f19",
|
||||
"0x7da805659d8b9e3f6b14aab3a5bd8d25e9d2d960076b4baf6c394a02fc763d12",
|
||||
"0x5491cc6940517e3a790bf6e32437537e0241c9fcb3302a3bf94133ceb65b8862",
|
||||
"0x0568a4d9b4e91fd1046fda2cb8a718ba57ba1526610013f465be7777e94356c1",
|
||||
"0x0831b1ce49717503b49502ffe6b854ab2eb2c4db30f5ea5033c011f5e5e3d309",
|
||||
"0xabd50d7ea56144421474763563ecdb591ec1df8645ccba4e28990d8b9b8ed16e",
|
||||
"0xfe4ceb9425449bde581ef04b46c1fc7bdbd8f422c43d64b2d1bbbe3ff4dd7a26",
|
||||
"0x489137c52ef8c71e620220d8e9e842c2a5befa812b70b0a709ab4603a729047d",
|
||||
"0x8fa480e08230c6b9d964bca0bc5d5a246e4eac6c8d45c75a4cfac8c4601f455d",
|
||||
"0xe5cde020c71c0ad3e7f9a789247e5518bc1b824b4c6297e12d09a42e265e4bef",
|
||||
"0xd4c0b9e39b70ef4f229884817c317f20f53386969f8c1e2ddc69cfa57b1014f9",
|
||||
"0x75b91e206eb0a2fa7752da4d6421fc294a4cd7d6d06dbdeb7b7df50e157ae99e",
|
||||
"0xa650044c8fb1c0d98b1e671d576f389b0b7be37e946b7623ff6203ca72c574aa",
|
||||
"0xe6dd07898de5688be966dbc612764a9956ef1105a7a02695ea269b6e40ccb077",
|
||||
"0xd1c7d40ae3558d4b42cbf6bce332e718ed8f9b7026b81195beea713ea9fe81da",
|
||||
"0xdfd6c816adcdd1a588db0bbb4c09050527a107bcc47d76be91c7e309a54dec92",
|
||||
"0xa67e60d39fad4b6389908ced2c0b6fc4d0b1ae78379de0452963589cde410618",
|
||||
"0x88a629bbfd9f5ec014580d47210562cc0ba162fc2e7f609dcc34babef9d2f89a",
|
||||
"0x685dcd734516a666b7e9018a420cc1ed6f1cd13d13f54dc782d3d2529bafd375",
|
||||
"0x00adf1bec319f440e54009e1ffc45d58f38a120644a111239aef09d1f91c20ed",
|
||||
"0x0ec349f19c0374334a6f9463b349e97c6a6696984c7779cf29bf048a6317224e",
|
||||
"0x0f190a67c3804e6aa618106b554578687d0f3983c8350709362fb7e4728adace",
|
||||
"0x7af75c91424ed2a01f0b796ea4772780395cf77d4051c91552fcb962a384a04c",
|
||||
"0xa43e2914fa364effea580b8d8ae6d7c5480acf7b9330b226438c12fb5e478ea2",
|
||||
"0x38deda38720cb7918d43b4b7296fa0168d77ffefee1217bbe198b382fefade22",
|
||||
"0x40e97169e2871117267eedd1095f76d97719f6e9dec56b3423a9258bb09815d7",
|
||||
"0x3368d112a868cabf7d21ea1c5c851fe0a37551c03d72cfd6b235e3a904eb5889",
|
||||
"0xaa25f4d9f97ca1cdbda79c61f1ab84883a037eed60d9ec2301cdd5c404c9805b",
|
||||
"0x21132089753a085a0a982388817137c591a9a34d2cd9e6651c57c76a8b80b716",
|
||||
"0xdf0c2df6ca5680424ac369b411ce78031614632c5fe44e2d8af1ddac30cd729a",
|
||||
"0x4f55598eecadc5136e90d15fcb9f87e1eec65ce18121127b49cd159c69c94098",
|
||||
"0x8a6b7276e3def38187b0cf9156aec251bab76637505f97583dc4d426ec86be50",
|
||||
"0xe8a516509c5bcb7e81372ce88f7d51982e092ea93f895e5dc666ddaea58edd54",
|
||||
"0x3edb18c971bd2f867ab6dbb3d63228aa94ed0d0eb9f603af71ebfb201095b836",
|
||||
"0x0e7de89c28113289c1f84ed91c289328b9cac13495b289ce11cd1c5942be1188",
|
||||
"0x2610da85e8fb400db625442fecb8cbe20435e8736fedf3bbf715501697ae6be0",
|
||||
"0x5668c3a61683c91b17467e48b2f27c7e377010eaee64c69d53ecb1ab89dee1e1",
|
||||
"0x58bb1cf79609e7223f1883dcc6d80538e278e514b1e11c6c2871db55dcdd9914",
|
||||
"0xfd8faec518007958057845c7b9f204c8dd473db5dc19ad5f2460802b1fae2693",
|
||||
"0x304b287a3513bf02a35fa61a8cb6aeb214d453d9d53213f458c207d2e15a537e",
|
||||
"0x7b8f9c4775a775637d9e3274068df7c5330096a52750d604e6f3818c4a7f0b15",
|
||||
"0xaac892295bff6dc1d99e51a4114857a5fffbc3c8b2b24bd057156c91a5e3bf7a",
|
||||
"0x34266cdb180c5227ebae64b8ddbecec44a6144214b9412d723924a92fb4a93c4",
|
||||
"0x1ed56966b89b57904056fcec5d2a23ca5a5d809a7f5c889c5123e3994d660398",
|
||||
"0xb44dde8ad3b29068b5d3b3551bef7082d8f09366ac622e57f6b494bd594c7a03",
|
||||
"0xabebaf98aa2e70020b83e45d5ab56164dcc58a4493264cdd6dfff3e921b395aa",
|
||||
"0xdf26e98e5499f58665912d987eaebe8234eec92c9cb4e788b274b9e9cc8b527d",
|
||||
"0xdb1f809c70c5633bac0f1642ad929984ff56154b16e0d81b8fa6b10706336c3e",
|
||||
"0xecc6cfaadef8dab02149f15d1f39932e53b3fcf25fdb1d0379ef9b933222c018",
|
||||
"0x17351e250078e53f17a144aad0933172ddc648a8f2fc530f0d4468623328b43a",
|
||||
"0xb832ca94746ea0be489afd60548e74d654278b8a08bffdda83f87e58459769c8",
|
||||
"0xbe1d486c25ec6042a110acb68d2fb9daeafb830f1d739506213b5a0de51887b5",
|
||||
"0x560e8231a58aa914a6b82977734a8ce364d970af688f014e8957933ca3026d66",
|
||||
"0x76b6b1959f5e0579fef78f6549b171028811c2fd64265bafd701e0a2de9d64b4",
|
||||
"0xba8ee49b308ea0c0475cd30b90252f4909063b86119e4d1cd53dcf6b4671b0bb",
|
||||
"0x168bfb6c2fd68fd7194561d6b0f6f76e733dfa092d550de243a2a7c0e6b14fa0",
|
||||
"0x8d5dbd6b82c31c1237d84256a837ff86e005033d83622531bb00de243da0e5f4",
|
||||
"0xd12f68a021b6f806c9d75468486f2c4fbad295ec51c0f507c445fc535a0caa81",
|
||||
"0xdbe40f0f8ee88a80512e2f9162776abf02218c6dfb61a36042ba973ab55aad3a",
|
||||
"0x6cf853351f1371aacafc02da272b304b246176c2867377185b349c5f5880257f",
|
||||
"0x3f37a65caa18187a3552e300aab18b27d4a2b2a25c049f29e5d8d7a2c57af78f",
|
||||
"0xad59d1d4be0ce243a38e94ffee6b21fe073b28b0bee9b0249f560219e9bf604d",
|
||||
"0xe28ca7ade73017341acecc09a647c6c0e638f6ebdf1566b534dd27d5e9ad67ce",
|
||||
"0xe3577a39c6d3670d2fcee9f36bfb4e79bcbea5695013ae037a7a7b4c5302979a",
|
||||
"0x56a8566c6bb04d61331e9950a97248e152742d6f0408a77258c102efde79a0bd",
|
||||
"0xf199dbb8b24df16441c45f5db31af6597172dcff5bcb84306a3f8ee9e7ebdea1",
|
||||
"0x85a9e253bae3c1c5064f320911e7f964c7315602e83374f5df7ba532cd2acefc",
|
||||
"0x80ce75ad1b2de3054cc12adc1774ef8e37f3123387d06daeb545953b7a2bb044",
|
||||
"0xb26d9c8ece65562068826bc872a6fd93e76634b8b7b598769d3df142ed5d17d2",
|
||||
"0xa43a1662961c4bd1bfa93fdf911067aca94460c733f5a9e296f9e47740b6f8a2",
|
||||
"0xf84716d76638301b784430585722e4c112375a69329ac03fb8e98882fbbd2fb3",
|
||||
"0xbdb1551fc7d0e24f2096586ea482b83b8603db1642ba6aa12d8369214af5e4c4",
|
||||
"0x8f8f8de670e0dc95346e2b14b82bf8a63d9a2a4eca385b1fafc19964cf98f710",
|
||||
"0x6d3f91249ce7f7f852a4ffab23b7e949117df088f2e2aa3db0fb386755a16c92",
|
||||
"0xeb9c005485707baed2b7ab034e68597bb8be65bd6f8283b690cd338bf7d1826b",
|
||||
"0xcaa884959fbea1f5110d7cc4360c24b2ede43d32f8cba522d28946ffd2d900fa",
|
||||
"0xa561dbe805f8ba3cb6d3d1524c4b3bcbc95ac330e6d71d33642412f8f0a1a2a3",
|
||||
"0xf158b9329dbbb90083c88982656840cb134713ba122e7e39b287bca4b0605dd4",
|
||||
"0xee3ce79371c0f0a1ac399a3a722a1c7515f6b02d2e03118e3fb6d521e245ab6e",
|
||||
"0x1083d6dba68c10cb19935b627e5576b5bc4e7904c8ff59657ced1c8397468017",
|
||||
"0xa893338e4a49166bd36f4361799c7cccaaee211b512e0c8821136cdb823e8ac8",
|
||||
"0x1327e2948ee57993f1b721e9fedc8f7d2e91f041b3e01340375bcbbdead83bfc",
|
||||
"0x6bc88c663e475911e9fbdfb9a33931c34bcfff5e533e82059d33cd69ee414d94",
|
||||
"0x81d95020affda45f536e01b1a4b840eb72afe2e82633d81de11acdeada45d93b",
|
||||
"0x91e59cb7e3729c776c4dd441c3377659b37fd881760b9e70c73d5288e99bfa0a",
|
||||
"0xbf69325ef2072cd5e3d2e93b8e6e2abbaa03434212e1ba4d36459a0f064a64ba",
|
||||
"0x11f4a2d21c3145af81ba0edb80a9c27cf1e2d53b1a43a42b58b49d4340ce4fa2",
|
||||
"0x8c366dac642346ca05e2fc047999f9adcab3b8166482854b06c77c2439e0655d",
|
||||
"0xdcae4952619f997d791aa6a973f1c8c1d3a0c21859b0c37bec64533a6f7c0630",
|
||||
"0x5300c16e42bf43e34c9e59fc5748c3e05d38437943956eb80ae91cebb4e33d87",
|
||||
"0x40ec29594f14d9d9a76b13342face2565914b050cc5e5eb96299c51ec92a529d",
|
||||
"0xa7da6ccf5a72ad5b8cfb6d00aed5f9f7e2bd70670c57873735ce976249fdd5d9",
|
||||
"0x177a1ca473ae2fb06ed39e180567da24fd14faffa062edbdcb0cffe4520045b9",
|
||||
"0xea7c63d98ea30c23e0f4df53566214eda57c96f9449aab5a02c165ddb8e61bd7",
|
||||
"0x6bf4bac02febf1f9459a433d08b373143f44c0beabd3f7bce4218259e8d91311",
|
||||
"0x6883559d2ed97c78d0aea12c0d14f0dbc911db36a3bd9e3f8a7142e1083e118f",
|
||||
"0x999416083ffc7371c9b95b6d1bea32da9c2b00827e1f0e1f615354dfe76dd5aa",
|
||||
"0x82873c88efa3041aae1d36c2a787e592a7af56c3d86f321b1dc619b974c88ff6",
|
||||
"0x6bfb4371b0a7b9eb9e3fb1f6987854d6e4210286b98bf8dfe6f71f12014ffe59",
|
||||
"0x5502ec7d23c5559afca6ac2d6178c1f2c778e4dca22a6bc8b16619082cafdc00",
|
||||
"0x97307b650b949382bc80b6ea446b629c0fbd37bb65a36ac1b33b1e4ac310c056",
|
||||
"0xe33b1569d06b2b5d05065c11a0dc4f22d214a7a4e4003c1888f7469094330a8d",
|
||||
"0x691870ffdeabba194cbc10492332d51702d75c40681662fcbd5489753bd5fcaf",
|
||||
"0xd9676a94b8e3eeac02389ca8c0a6d730e2718c0cfc3a5bab3110aa170d64bbf5",
|
||||
"0xf558d9d27beca0657bd8ca7e82d1788b1777dbe06b474b7598acdfd46e8030cf",
|
||||
"0x381d766d66669a50d13a141535c441887cad897984d7b2bd52e9bf33c385669c",
|
||||
"0xacbc99a6cf54ca6fcc9ad8f844f8bbd7639791b663956cda2ac59fed34027024",
|
||||
"0x04e5b5dfedaa9369bed72fe0ce827e3c16e7a07a274661d76ec92347baa8deda",
|
||||
"0x2a905b1aa12a30fb04f56b2d9a26a38ce10cc2e9dc910f213ec3c6b368b15bf0",
|
||||
"0x0f40416a8bc6d699c404972d27c9b69093b387a78f22295cb0a6001cd437a4fa",
|
||||
"0x05a52a1501ff0d2c044f0c1932e5eb217aa734cabd527d865796fdd120fd8856",
|
||||
"0x36c70cc55f4b571882ecab711522e4bffd3ae8f6873d940a0e4626ade7797612",
|
||||
"0x4a7af1b12b32d3bb38ec4aa0cda6535cd96043466a56f0641253c7b21abe9205",
|
||||
"0xf637f992df45cd4b58d2db4d5c8360a65cf05a11f14dba70638e50b5bf70bff4",
|
||||
"0x5b271fd0d5a0adaa16218fab9f75e0599d85c093233761a76c03ba060d5b7948",
|
||||
"0x8e3554617c506afbd2eed41a4c8e2ecc1bf619b163843a983411c884e5b07320",
|
||||
"0x96c35e763be9f9a95f76c81fbe1659d22715f5cdc0cb36c168c67a1062818914",
|
||||
"0x1d1235e2789d0d283a3d4c06e391a1e38869c788255facbaca7e23c4e76e5ba4",
|
||||
"0x25246df476679b7364020ebe600ff596b6eb17b23c68ab05885a02616bd2e5f5",
|
||||
"0x0a516b13c9e864bcaabf531c43ed3ca725d4521c9d34ee08280fd13500cdcfb5",
|
||||
"0x15b0defb12ba7d05f4c5b387efbcf5eb41e325ece9a0b83619a5b7e19283b677",
|
||||
"0x5000d5c4cad2ef87de73eb2f10d6733a840d069200cb30d4221031381e8c8f36",
|
||||
"0x15e98f25d14ef227fbca0b760e2d436e291d3668498f486611a6a3118f5a8556",
|
||||
"0xdc0d786b90d673f30f84706d29643bf0c392464f30ea66052b153ec28ee4b7cb",
|
||||
"0xe4da2a6b7a254b85df06dbe8f2bf24b4ca3ef6d5c3b0fc8c17e0ebd32d5d69ac",
|
||||
"0xe2e6fe80f327eded1c263684cbc525e27839bc816b237588b902c66623c38eb7",
|
||||
"0x1b8c963829103769fab68bdf45dfe4d6130abc9560590871665f23b190e959e6",
|
||||
"0x5d2e7cb7a42acaadbc832fb8974756f9473b18263ea50aa281fbcfe217a15762",
|
||||
"0xcf46e1381d84a33aa488d4674b3ac43a1b6afb102c7a425fcc1447769ef5e6f9",
|
||||
"0x00532839fe3e0691e406d230c8d384b6bc562923048ea0d89f1be054252eee58",
|
||||
"0xa68d5545328145a3dabe1b143a57a13057d14866c6b9c9da8b4781f4efed4945",
|
||||
"0x5223699aa191c964875eb16507aacefde636e88c0f0093d92bc38be221fb3792",
|
||||
"0xa9b807ba38a8434b3befcc91f6b93427dc81f365354f62d5ee69730e319ce5d9",
|
||||
"0xfd0dd9977372d780c38981010a339dd6552e8f81fc7654362590e7c6b9fd1f6f",
|
||||
"0xca3900d2a87a6e0b04d679bb87dc81bd1ac11e79e4f0355e314c7e41d76de4e3",
|
||||
"0x78ee224a33ce3b2629f7640392846f17c228288b89d6c2d9db42726cf64225cb",
|
||||
"0x48a4acdd0758838c9ce2b322bc77459c1cc0fdca3d588d60697c8a5aa3035273",
|
||||
"0x6eb8aeeda5a4b26e73ac2bd7f838c974b5bc45de138d14ba58b51bfb6d51cf93",
|
||||
"0xd6895877c885791db924b0ab1a1d666c06a10e6d210e02cf9c2f29726d3c565b",
|
||||
"0xcffa80c70e6246e7b17173c071384a7b46dfdd5ab4b4b524c88871ca02c7e658",
|
||||
"0xbf64411370653f8e08373438b03ccff7fc6ae1d70385cd26a7e73b57da07dd75",
|
||||
"0xd9a39f3b774d208608c7d1d9d1fcdacf0c0ff6e8cb7915bca57e8056a8b914c9",
|
||||
"0xd6a1f8fae6440d4ba8b2e392dbd07f6dd6290651a221b3749cd2dd6b0f39ba0c",
|
||||
"0xa1ad925960651423f598ab111a0f2bcc5d3fc7f62fc72eb2753815277183a4ac",
|
||||
"0xf3f6feaa55dcb3eb9c572404a0da1cf7dbb53983a98873b3f0398aad91773b69",
|
||||
"0xdb902ac0d33bba7b0bcfbbe3b5533b970d07381fb00a973b4dd92c8f7af7bcb8",
|
||||
"0x5f97ac6dd3f55bbf179eafc50c64042f2daccfcb3bae9c4305045b709cf19ae2",
|
||||
"0x7061adfb4514170759ff4ddf3922b10f2c85c1a65c361936e504ec77df84b703",
|
||||
"0x07ae6b39e66142978d35c4c2a517c55c23ec47ae341557e8cbe8a0d001df0f6f",
|
||||
"0x0e6b9fc3fec4e75d812128fbbae0946dc48b511b198a5301833992e763423da3",
|
||||
"0x7e1da14382f9908299fe46dedaf1878a6d01e9070554f1436514d320e0a4ebc8",
|
||||
"0xdb6cdc7239c51386bb9eb371765cccb84e4e4de38acc5ad7e5503bd0f60a31a4",
|
||||
"0xcd0069c9fb9ba8d136a2020580827799eac95f613f7b75bce8322fe67ecdc2e0",
|
||||
"0x06932b0dc851ffb7ce68ed9083cecb5ba074716f188c5bb4df94de8e7e057046",
|
||||
"0x3a2e83e02240263c4e416898f9d54bd0b579ddb0076537b58c47c3a17df15208",
|
||||
"0x61b166d6dee81bdf6d101f23bf8ca40b74c2eb3f47561b4ef024d30f410f88a7",
|
||||
"0x7a9e85a9000cb7308a5c57c7b1421b22f63e64f48630a79e449e7a207cf586a1",
|
||||
"0xd573fcbaafb3882fdb1985c1b939961d35dd7bcbd5865be82276d0cea1afc7a8",
|
||||
"0x697152abd7502169e0d801346a41c815d8bd8e75e55845d4a4b251def64a9583",
|
||||
"0x77e5cfae8dc5913c4bbd4f4d84a797bf8919a0c21a4eab4f5dfb42fe8c5019d3",
|
||||
"0x6e7af8bd163f679b81489d3ec3cc4948cc57ccb3e0c8cbc80e387783bb87641d",
|
||||
"0x4bd5ece25cfda291179b8977a84369ab1590c9d4d5b45a24865ca010e5ffa676",
|
||||
"0x6331f61c715be1fe8e0c90740cb89c0a7cee24524be2258ad49542959f845477",
|
||||
"0x0af729bb18715399a1b07ffe2e0d562f71c27ee2bc01921c25327d421165bef7",
|
||||
"0x98ee97e5bbeaa0715143a39f38ac56736f54fe5b971584b4061c58721c051a3f",
|
||||
"0xd06e19176339b1fb5cf469b1f0ee4350a416d20aaa9c1be50bdd26687b2424bc",
|
||||
"0x2385cde28be71e40f64ba5db5bd1a8e5f4b767a9a17c21a96fd2642ead428394",
|
||||
"0x3d2ef2f0e4bae5c2ca6fb9fcfa1a9ffc435471a7a533b3b7df2b28402d335f58",
|
||||
"0x2ecc6ed70661e692248c80735650c253dfe6b3c2213bfc259ebc70c898ee8e6e",
|
||||
"0x8a68b3eb663796ca2189e49b9fe5902e36615d03d28ac34c01f63a135b930f0b",
|
||||
"0x563d7efb4175fc12dab431175b5097186c2379a5aca1901e39d641d02865d426",
|
||||
"0x1a55cf9842f9008e0730ae9fc6af9f288edba323803d0ae787fc0fdda99be8c9",
|
||||
"0xccdf47cee7142cad27bbf224f0afd1a6e5178345cab510f2f8ee27115ab27ff7",
|
||||
"0xc5b3582937ad993c5c234d059e6cd3b98f2fa4e3fe4ad591ecb6ae710b51fee9",
|
||||
"0xd651ab199355d61c49e63259e6a20d17bf72b27891271e5175a24c23fb2dc29c",
|
||||
"0x800e1e33b0cd48afc6f8f7c69b85902ad93e94bb290b35a862cbad67706a2f3d",
|
||||
"0x57c7349a6b630cb52c3c1205165df428ed51e25cc167c08739f86bfa46c69e48",
|
||||
"0xb393d362daff182dafcce65eda9038fc0c8908b3cb1ec1a1218570211c34e142",
|
||||
"0xb2f49f7a836cd0db9e4743158ff80dd97d23de7a39a0438d19c79c355339c43c",
|
||||
"0x3f46776ec25b5c67468c32c1b2ca02910a7f46b4b62b5dc5d0cc6b9d3381b958",
|
||||
"0x754c4ea722e501668aa48d6151ff423263b8a4e2f33b9e44e189ee4e78462741",
|
||||
"0x12e79ee2724763a8a7f9196bf4d0e855e0ae3f75f5a697d90a263bf562acc5a3",
|
||||
"0x407b168fea70128a8090ca86274b0b8e7965f16d54ea2b3bbabb378485b22a02",
|
||||
"0x0d1557ad0cb1466965e6ee86c5ce887eedf462dbec2e719c5f396f8ed95edf08",
|
||||
"0x29c3a0db9f83698e6ae703174dbeec06f3d2055eb933799e4ae3bf73f4570dde",
|
||||
"0x8ade20e56fcacb40f54259696bea1aa04d839b88c503d6775d7b4491e0f9e7fa",
|
||||
"0x327ef0f173632c5049988b312b1f49e9948b02125f70e117ea127088191c32d5",
|
||||
"0x2989c11c234b7fc5901e168d7adfa655ff6165098eb94d244b623ba43c6abbd6",
|
||||
"0x10b56dc8f023de6a8f97696dfe2993b56156a9b35f671438fee5830f52b633b5",
|
||||
"0x46cd37fffe94a01297f2dcef322ae72f58bbf9f58bc9f930cbf56e73f8d5ce13",
|
||||
"0x2240214683eafc37396f3078446b43ae96bc576e45db650b953ff87a895ee7d7",
|
||||
"0x0db4d500e5755cba5b962f6b83942e72fd1504cf52531916084852179669a08d",
|
||||
"0xafc686a8325a30966db0f54b64a4e7235ea54e300d280a4d2a502651a53424b5",
|
||||
"0x59d46f6fb8eadcf18e31c9fd0da6844d63a2dc19eeeaf9ad5b80113aca5bc42a",
|
||||
"0x153ae496364bf7c34c8c967e044cef69e401f0e4aff27b04808e2c299dcf15a8",
|
||||
"0xc85b8d3156729c7f8ff1989f320464144f4918140d608cf03e7dfd5b51ec2acf",
|
||||
"0x78fd0613f6f5291d4131152225fbded5464841a119d854a7550a1f178a8cdfc7",
|
||||
"0x763dc1a000b949a45f792515fed6af70047641fa3d7beeb50b141c27b4f8cd33",
|
||||
"0x42567a1e6caadaa10a13feff343ae1e2a903564affacc48aebc14f257db58ee1",
|
||||
"0x62c208337234d101cc95cb6be54c17631e26c956758493f5bb7978faf0ace984",
|
||||
"0x7977aec997a3029025ef789d3492755c80c2d028046aae8c4b926f247e1981d9",
|
||||
"0xf927505a0c29231ed187a884af15a82dbc48a1cb002f6d91496f6569c673682d",
|
||||
"0xefd2c54f6d2483a3dd7b994d8afa5441cfffa956d7da6e81bbd1691e07ac7519",
|
||||
"0x7bcf94d8927a39dd00558763cdd2edaf40d55728d720dccfa0f5e1e827079cc0",
|
||||
"0x19c7e5115ec25b14bd85e3d368e15d2bbe60451ed9a02f03770a3e845521b77c",
|
||||
"0x60e32d48de6979c70dcb3e3f068fc3632aba5844703d50851a34975338b3a837",
|
||||
"0x6722f01dc1d6dd1f0678e5b527155beb0616e33887697a56ef4cc1bac642f394",
|
||||
"0x59bf17368d69e0379f0f20ec1b1b856298b8d6b4c36354ee765c8a894e58ab9b",
|
||||
"0xe2559e7b67a15a3ddfbf1ddc597a1309d1fd780fe26da28aace16ad31754883c",
|
||||
"0xbf687ac704bf02a3877e72f738691bf5027c21f64c68a50235876a8d015ae682",
|
||||
"0xde01838df621b7368adf4fda268c827dfaa6753a39d51956c0445a2244585ec1",
|
||||
"0x4ba14d3860d1dee44904719e45a5bfe54dd1e4c9bdafd0a41279e432a021f2e6",
|
||||
"0xa2380cb32538cc80e07fda5575ecd7b35e0c12932687bd8002da652ad8c16dc2",
|
||||
"0x82d0f5c8421d6803e52e3d6a37eea0cd978686792a2f6d175d77e9c75fb4ad86",
|
||||
"0x23701b29d07c64c998ee4bf8199d5ac0f3d9724af2544cc29665a1d92a6dadce",
|
||||
"0x8bbd490220c823506e111c668f923d18addf5a23d9b5244103cc135c4335f23d",
|
||||
"0x190506f2d9decb8f9423662f406e61c99606abdcb369e25a1a89c2bdc44c6158",
|
||||
"0xb9504b090b276cbbf86349bc4dbb66b46a42ce6ae8d44d5cd7f39773fdf6112a",
|
||||
"0x38fc273344dc7230790963dfb3dedfabe142c18886d6542d77ace8ed6d117c4f",
|
||||
"0xc76929e9a3a984f6ab6395c4811f007eb6d73a86fe62f8a1c02e860769f2bcde",
|
||||
"0xc4fc2465f71d06102d232858cfd9737e6e82311a45b1cb2ac203de80c881a2f4",
|
||||
"0x34427ee5534de01e7f0510b87e6f45aac6210897472978aee3c051c39776c561",
|
||||
"0xec4f3c6349dac1e7e43b0541b1132b3d0cc8bd422436f31832184d1aa6f9c822",
|
||||
"0x024a848067a1156852c78495581392774b00f22e32021ca531afeab1aafb683e",
|
||||
"0x9bdf793e30326a181d3d8fb3f27818475b755e3d1fea200d8c514cf17024979a",
|
||||
"0x55a1d92354a31354b4b1d9366e98b27c0467b01a108d67dab7feeeda23f981d9",
|
||||
"0x74614ac3de92173d07434dd80d83aad5c1d551127896298808ad7fba96051e06",
|
||||
"0x7bdb77183ca1e7f50d292e50ef701ad3bfff3e6e28d36629c5325da03cb8d013",
|
||||
"0x3a35dc3d12de1053d204410a577b9e5c36d32fbda761f797aee248c27f7dbb02",
|
||||
"0x430aaeb1dc02bb792375d1702999cda7c384dde1c6f46ef26f1e26e5a55dfd87",
|
||||
"0xe12805d1713ba730fec6aae824bdcd0a896c6d5e12b9bfa5b6e0a2c2be251c17",
|
||||
"0x5a297bd3be2352e56136db83a76c7041ef825128152366b2d8f032abb1d6656f",
|
||||
"0x111782d82f50ea25d684af38689cea53319f1a88557d82c57e46ee5e75f99c05",
|
||||
"0xe12520cda10064d74fdefba22b5ff4c5eb95508f77fd7c8c3fe82fb89e165bf6",
|
||||
"0x6af12e8f4db19aee3865c3d681073e7433d902832bc651b8fc3f5fd038c8bca6",
|
||||
"0x82a4a2ce19ca3fd99007279d62dadba547b6818607800e963b3bc53c5541298a",
|
||||
"0xbf3a444d1b15d01a29ea22d05e71021ee3581338ecc9e770ee23ab6549a19d55",
|
||||
"0x745ff92172b5c83cdd69265b919028b350ef95a01c84810366d630162fd9b07f",
|
||||
"0x6128cd2ff1be9e56396a676362a2049f3e670c70ad2a77be724c090fd4085f0b",
|
||||
"0x8ffc6bf8165e52ecf30ec955d4be1bb093e6074c92a527382a8892ffa3d3e7f7",
|
||||
"0xd65bc11ef24c0fa476640d9effdc57030a86f547b7aa79b209954a6abf4072c4",
|
||||
"0xcd5b5e184a5c0d1c5bdd12f80736ed1a4530210b4ef5f35dacd3feba722a334a",
|
||||
"0xa80657ecf79ef03fb919bf312e02d94ab528c1b5c3858332d9bf82f807b1c232",
|
||||
"0xc67dfe4aca5001e97ba6f401f15b72be85ae45972ba98b965a6dd4954d5c2386",
|
||||
"0x59201e892aeab9e40aef69945585b81b47a7444ed61ba6c6e23e006103ed7edd",
|
||||
"0xf535c920c5316f12f0bfedc298fbad028dd84161927414b14243c4c5ddd4f4f1",
|
||||
"0x66c6e42c8137c043eb49528c718b10e5dbad9164bd3ffcc6b55b4b0501dc507b",
|
||||
"0xa60b9485cb54818e0b0bfe4faeca923915f85bbac0525d09d96f375d0b2b9f81",
|
||||
"0x8f9377dddacb6ed605c8ed8ed2bc6e2323a4e5d0c9b29bccdfbd27f57a9ec315",
|
||||
"0xc48a1940c424c2df4803ba8d5573066ce4bbf0e0fbdaa87abcb2d2f51b0a4602",
|
||||
"0xc7bce918e9f897aeb1351d2c9cbc2fbc8fd674017cb25c49846b05d609f00ed9",
|
||||
"0xcdaa86e0c026c91954c6305cb7ce6010560f691a2667baf0e95bc18cd3e067df",
|
||||
"0xf131e0910a8088fc5b0b1d2e93e31632eec67fa88f75bc4f9c3c1b0a317e1d54",
|
||||
"0xb4f8d72a85c4c2261c7b00f43b96d7d749d0e53359993f52517da36de4c9559b",
|
||||
"0x73f84bb4774a81b39b3a10d18c7a2404d21f3efd26301dbb7c8136e96304281e",
|
||||
"0x5559435a987f1444e4ec78b8530009e49c52431b37c7e9f80ce2e056d44e876a",
|
||||
"0x070664d11ee10c4e0475a7ece219eb0e606e055ee0fa1266b669e593b5ba1d87",
|
||||
"0xfdfafeba7b5551d1e2d6f179be5ddfdbd0350bd2e9dfea40e272fb608549e8c2",
|
||||
"0x50a1356bab9b56d8ed46a3e8f55b8a16af42df6b15fcc68aa548216de484c7eb",
|
||||
"0x681161a307552ff12175074601005bae0c6f7b38cfa6dcb87975a1df205e28d5",
|
||||
"0x2b39456efc2e8863197c95a4d6eef5069612cc2aa6414f0991393ffa672a1a15",
|
||||
"0x571b916a82371fafcb456524655758bd42b4f7b768e13807a1a995e642ec205c",
|
||||
"0xb2821504201eea0e6040a131a709547fc9afb44ba7bfa6a188201735753ba3b7",
|
||||
"0xb16a8af1bfdde1fae0e28f29c6db0b361840df4b55e73bddffbc1cc11bcc5584",
|
||||
"0x1df38b594f536cee38acad293a818bf83fc67830fc71bc19790d7733a2caab60",
|
||||
"0xebb3e8f76f3b6a95285154dc11d4bd94ac4c3a150383ed69f5373499b1983dc3",
|
||||
"0xb0919ed300acac5f912f01611a428861db27ffb8129a80495f735f0ac608ab35",
|
||||
"0x2ee321d9d805b78a97210df2977ab62b352705e308773b90e0f4e923adec377c",
|
||||
"0xee00cb02e9b86978ae10b119924bbe6c38f730c1d1b621d32c9d697e11105871"
|
||||
]
|
||||
},
|
||||
"nodes": [
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,17 +14,18 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Silence: `use of deprecated item 'std::error::Error::cause': replaced by Error::source, which can support downcasting`
|
||||
// https://github.com/paritytech/parity-ethereum/issues/10302
|
||||
#![allow(deprecated)]
|
||||
|
||||
use ethcore;
|
||||
use io;
|
||||
use ethcore_private_tx;
|
||||
|
||||
error_chain! {
|
||||
links {
|
||||
PrivateTransactions(ethcore_private_tx::Error, ethcore_private_tx::ErrorKind);
|
||||
}
|
||||
|
||||
foreign_links {
|
||||
Ethcore(ethcore::error::Error);
|
||||
IoError(io::IoError);
|
||||
PrivateTransactions(ethcore_private_tx::Error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
//! `ExecutedBlock` is an underlaying data structure used by all structs above to store block
|
||||
//! related info.
|
||||
|
||||
use std::cmp;
|
||||
use std::{cmp, ops};
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -52,7 +52,6 @@ use vm::{EnvInfo, LastHashes};
|
||||
use hash::keccak;
|
||||
use rlp::{RlpStream, Encodable, encode_list};
|
||||
use types::transaction::{SignedTransaction, Error as TransactionError};
|
||||
use types::block::Block;
|
||||
use types::header::{Header, ExtendedHeader};
|
||||
use types::receipt::{Receipt, TransactionOutcome};
|
||||
|
||||
@@ -155,69 +154,15 @@ impl ExecutedBlock {
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for a object that is a `ExecutedBlock`.
|
||||
pub trait IsBlock {
|
||||
/// Get the `ExecutedBlock` associated with this object.
|
||||
fn block(&self) -> &ExecutedBlock;
|
||||
|
||||
/// Get the base `Block` object associated with this.
|
||||
fn to_base(&self) -> Block {
|
||||
Block {
|
||||
header: self.header().clone(),
|
||||
transactions: self.transactions().iter().cloned().map(Into::into).collect(),
|
||||
uncles: self.uncles().to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the header associated with this object's block.
|
||||
fn header(&self) -> &Header { &self.block().header }
|
||||
|
||||
/// Get the final state associated with this object's block.
|
||||
fn state(&self) -> &State<StateDB> { &self.block().state }
|
||||
|
||||
/// Get all information on transactions in this block.
|
||||
fn transactions(&self) -> &[SignedTransaction] { &self.block().transactions }
|
||||
|
||||
/// Get all information on receipts in this block.
|
||||
fn receipts(&self) -> &[Receipt] { &self.block().receipts }
|
||||
|
||||
/// Get all uncles in this block.
|
||||
fn uncles(&self) -> &[Header] { &self.block().uncles }
|
||||
}
|
||||
|
||||
/// Trait for an object that owns an `ExecutedBlock`
|
||||
pub trait Drain {
|
||||
/// Returns `ExecutedBlock`
|
||||
fn drain(self) -> ExecutedBlock;
|
||||
}
|
||||
|
||||
impl IsBlock for ExecutedBlock {
|
||||
fn block(&self) -> &ExecutedBlock { self }
|
||||
}
|
||||
|
||||
impl ::parity_machine::LiveBlock for ExecutedBlock {
|
||||
type Header = Header;
|
||||
|
||||
fn header(&self) -> &Header {
|
||||
&self.header
|
||||
}
|
||||
|
||||
fn uncles(&self) -> &[Header] {
|
||||
&self.uncles
|
||||
}
|
||||
}
|
||||
|
||||
impl ::parity_machine::Transactions for ExecutedBlock {
|
||||
type Transaction = SignedTransaction;
|
||||
|
||||
fn transactions(&self) -> &[SignedTransaction] {
|
||||
&self.transactions
|
||||
}
|
||||
}
|
||||
|
||||
impl<'x> OpenBlock<'x> {
|
||||
/// Create a new `OpenBlock` ready for transaction pushing.
|
||||
pub fn new<'a>(
|
||||
pub fn new<'a, I: IntoIterator<Item = ExtendedHeader>>(
|
||||
engine: &'x EthEngine,
|
||||
factories: Factories,
|
||||
tracing: bool,
|
||||
@@ -228,7 +173,7 @@ impl<'x> OpenBlock<'x> {
|
||||
gas_range_target: (U256, U256),
|
||||
extra_data: Bytes,
|
||||
is_epoch_begin: bool,
|
||||
ancestry: &mut Iterator<Item=ExtendedHeader>,
|
||||
ancestry: I,
|
||||
) -> Result<Self, Error> {
|
||||
let number = parent.number() + 1;
|
||||
let state = State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce(number), factories)?;
|
||||
@@ -250,7 +195,7 @@ impl<'x> OpenBlock<'x> {
|
||||
engine.populate_from_parent(&mut r.block.header, parent);
|
||||
|
||||
engine.machine().on_new_block(&mut r.block)?;
|
||||
engine.on_new_block(&mut r.block, is_epoch_begin, ancestry)?;
|
||||
engine.on_new_block(&mut r.block, is_epoch_begin, &mut ancestry.into_iter())?;
|
||||
|
||||
Ok(r)
|
||||
}
|
||||
@@ -270,7 +215,7 @@ impl<'x> OpenBlock<'x> {
|
||||
/// NOTE Will check chain constraints and the uncle number but will NOT check
|
||||
/// that the header itself is actually valid.
|
||||
pub fn push_uncle(&mut self, valid_uncle_header: Header) -> Result<(), BlockError> {
|
||||
let max_uncles = self.engine.maximum_uncle_count(self.block.header().number());
|
||||
let max_uncles = self.engine.maximum_uncle_count(self.block.header.number());
|
||||
if self.block.uncles.len() + 1 > max_uncles {
|
||||
return Err(BlockError::TooManyUncles(OutOfBounds{
|
||||
min: None,
|
||||
@@ -284,11 +229,6 @@ impl<'x> OpenBlock<'x> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the environment info concerning this block.
|
||||
pub fn env_info(&self) -> EnvInfo {
|
||||
self.block.env_info()
|
||||
}
|
||||
|
||||
/// Push a transaction into the block.
|
||||
///
|
||||
/// If valid, it will be executed, and archived together with the receipt.
|
||||
@@ -297,7 +237,7 @@ impl<'x> OpenBlock<'x> {
|
||||
return Err(TransactionError::AlreadyImported.into());
|
||||
}
|
||||
|
||||
let env_info = self.env_info();
|
||||
let env_info = self.block.env_info();
|
||||
let outcome = self.block.state.apply(&env_info, self.engine.machine(), &t, self.block.traces.is_enabled())?;
|
||||
|
||||
self.block.transactions_set.insert(h.unwrap_or_else(||t.hash()));
|
||||
@@ -344,7 +284,6 @@ impl<'x> OpenBlock<'x> {
|
||||
self.block.header.set_difficulty(*header.difficulty());
|
||||
self.block.header.set_gas_limit(*header.gas_limit());
|
||||
self.block.header.set_timestamp(header.timestamp());
|
||||
self.block.header.set_author(*header.author());
|
||||
self.block.header.set_uncles_hash(*header.uncles_hash());
|
||||
self.block.header.set_transactions_root(*header.transactions_root());
|
||||
// TODO: that's horrible. set only for backwards compatibility
|
||||
@@ -394,22 +333,39 @@ impl<'x> OpenBlock<'x> {
|
||||
pub fn block_mut(&mut self) -> &mut ExecutedBlock { &mut self.block }
|
||||
}
|
||||
|
||||
impl<'x> IsBlock for OpenBlock<'x> {
|
||||
fn block(&self) -> &ExecutedBlock { &self.block }
|
||||
impl<'a> ops::Deref for OpenBlock<'a> {
|
||||
type Target = ExecutedBlock;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.block
|
||||
}
|
||||
}
|
||||
|
||||
impl IsBlock for ClosedBlock {
|
||||
fn block(&self) -> &ExecutedBlock { &self.block }
|
||||
impl ops::Deref for ClosedBlock {
|
||||
type Target = ExecutedBlock;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.block
|
||||
}
|
||||
}
|
||||
|
||||
impl IsBlock for LockedBlock {
|
||||
fn block(&self) -> &ExecutedBlock { &self.block }
|
||||
impl ops::Deref for LockedBlock {
|
||||
type Target = ExecutedBlock;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.block
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Deref for SealedBlock {
|
||||
type Target = ExecutedBlock;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.block
|
||||
}
|
||||
}
|
||||
|
||||
impl ClosedBlock {
|
||||
/// Get the hash of the header without seal arguments.
|
||||
pub fn hash(&self) -> H256 { self.header().bare_hash() }
|
||||
|
||||
/// Turn this into a `LockedBlock`, unable to be reopened again.
|
||||
pub fn lock(self) -> LockedBlock {
|
||||
LockedBlock {
|
||||
@@ -443,25 +399,25 @@ impl LockedBlock {
|
||||
self.block.header.set_receipts_root(
|
||||
ordered_trie_root(self.block.receipts.iter().map(|r| r.rlp_bytes()))
|
||||
);
|
||||
// compute hash and cache it.
|
||||
self.block.header.compute_hash();
|
||||
}
|
||||
|
||||
/// Get the hash of the header without seal arguments.
|
||||
pub fn hash(&self) -> H256 { self.header().bare_hash() }
|
||||
|
||||
/// Provide a valid seal in order to turn this into a `SealedBlock`.
|
||||
///
|
||||
/// NOTE: This does not check the validity of `seal` with the engine.
|
||||
pub fn seal(self, engine: &EthEngine, seal: Vec<Bytes>) -> Result<SealedBlock, BlockError> {
|
||||
let expected_seal_fields = engine.seal_fields(self.header());
|
||||
pub fn seal(self, engine: &EthEngine, seal: Vec<Bytes>) -> Result<SealedBlock, Error> {
|
||||
let expected_seal_fields = engine.seal_fields(&self.header);
|
||||
let mut s = self;
|
||||
if seal.len() != expected_seal_fields {
|
||||
return Err(BlockError::InvalidSealArity(
|
||||
Mismatch { expected: expected_seal_fields, found: seal.len() }));
|
||||
Err(BlockError::InvalidSealArity(Mismatch {
|
||||
expected: expected_seal_fields,
|
||||
found: seal.len()
|
||||
}))?;
|
||||
}
|
||||
|
||||
s.block.header.set_seal(seal);
|
||||
engine.on_seal_block(&mut s.block)?;
|
||||
s.block.header.compute_hash();
|
||||
|
||||
Ok(SealedBlock {
|
||||
block: s.block
|
||||
})
|
||||
@@ -470,6 +426,7 @@ impl LockedBlock {
|
||||
/// Provide a valid seal in order to turn this into a `SealedBlock`.
|
||||
/// This does check the validity of `seal` with the engine.
|
||||
/// Returns the `ClosedBlock` back again if the seal is no good.
|
||||
/// TODO(https://github.com/paritytech/parity-ethereum/issues/10407): This is currently only used in POW chain call paths, we should really merge it with seal() above.
|
||||
pub fn try_seal(
|
||||
self,
|
||||
engine: &EthEngine,
|
||||
@@ -510,12 +467,8 @@ impl Drain for SealedBlock {
|
||||
}
|
||||
}
|
||||
|
||||
impl IsBlock for SealedBlock {
|
||||
fn block(&self) -> &ExecutedBlock { &self.block }
|
||||
}
|
||||
|
||||
/// Enact the block given by block header, transactions and uncles
|
||||
fn enact(
|
||||
pub(crate) fn enact(
|
||||
header: Header,
|
||||
transactions: Vec<SignedTransaction>,
|
||||
uncles: Vec<Header>,
|
||||
@@ -528,13 +481,12 @@ fn enact(
|
||||
is_epoch_begin: bool,
|
||||
ancestry: &mut Iterator<Item=ExtendedHeader>,
|
||||
) -> Result<LockedBlock, Error> {
|
||||
{
|
||||
if ::log::max_level() >= ::log::Level::Trace {
|
||||
let s = State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce(parent.number() + 1), factories.clone())?;
|
||||
trace!(target: "enact", "num={}, root={}, author={}, author_balance={}\n",
|
||||
header.number(), s.root(), header.author(), s.balance(&header.author())?);
|
||||
}
|
||||
}
|
||||
// For trace log
|
||||
let trace_state = if log_enabled!(target: "enact", ::log::Level::Trace) {
|
||||
Some(State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce(parent.number() + 1), factories.clone())?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut b = OpenBlock::new(
|
||||
engine,
|
||||
@@ -543,13 +495,23 @@ fn enact(
|
||||
db,
|
||||
parent,
|
||||
last_hashes,
|
||||
Address::new(),
|
||||
// Engine such as Clique will calculate author from extra_data.
|
||||
// this is only important for executing contracts as the 'executive_author'.
|
||||
engine.executive_author(&header)?,
|
||||
(3141562.into(), 31415620.into()),
|
||||
vec![],
|
||||
is_epoch_begin,
|
||||
ancestry,
|
||||
)?;
|
||||
|
||||
if let Some(ref s) = trace_state {
|
||||
let env = b.env_info();
|
||||
let root = s.root();
|
||||
let author_balance = s.balance(&env.author)?;
|
||||
trace!(target: "enact", "num={}, root={}, author={}, author_balance={}\n",
|
||||
b.block.header.number(), root, env.author, author_balance);
|
||||
}
|
||||
|
||||
b.populate_from(&header);
|
||||
b.push_transactions(transactions)?;
|
||||
|
||||
@@ -615,6 +577,7 @@ mod tests {
|
||||
last_hashes: Arc<LastHashes>,
|
||||
factories: Factories,
|
||||
) -> Result<LockedBlock, Error> {
|
||||
|
||||
let block = Unverified::from_rlp(block_bytes)?;
|
||||
let header = block.header;
|
||||
let transactions: Result<Vec<_>, Error> = block
|
||||
@@ -644,7 +607,7 @@ mod tests {
|
||||
(3141562.into(), 31415620.into()),
|
||||
vec![],
|
||||
false,
|
||||
&mut Vec::new().into_iter(),
|
||||
None,
|
||||
)?;
|
||||
|
||||
b.populate_from(&header);
|
||||
@@ -669,7 +632,7 @@ mod tests {
|
||||
) -> Result<SealedBlock, Error> {
|
||||
let header = Unverified::from_rlp(block_bytes.clone())?.header;
|
||||
Ok(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, factories)?
|
||||
.seal(engine, header.seal().to_vec())?)
|
||||
.seal(engine, header.seal().to_vec())?)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -679,7 +642,7 @@ mod tests {
|
||||
let genesis_header = spec.genesis_header();
|
||||
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
||||
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
||||
let b = OpenBlock::new(&*spec.engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap();
|
||||
let b = OpenBlock::new(&*spec.engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
|
||||
let b = b.close_and_lock().unwrap();
|
||||
let _ = b.seal(&*spec.engine, vec![]);
|
||||
}
|
||||
@@ -693,7 +656,7 @@ mod tests {
|
||||
|
||||
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
||||
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
||||
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap()
|
||||
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![], false, None).unwrap()
|
||||
.close_and_lock().unwrap().seal(engine, vec![]).unwrap();
|
||||
let orig_bytes = b.rlp_bytes();
|
||||
let orig_db = b.drain().state.drop().1;
|
||||
@@ -717,7 +680,7 @@ mod tests {
|
||||
|
||||
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
||||
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
||||
let mut open_block = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap();
|
||||
let mut open_block = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
|
||||
let mut uncle1_header = Header::new();
|
||||
uncle1_header.set_extra_data(b"uncle1".to_vec());
|
||||
let mut uncle2_header = Header::new();
|
||||
|
||||
@@ -25,7 +25,6 @@ use blockchain::{BlockReceipts, BlockChain, BlockChainDB, BlockProvider, TreeRou
|
||||
use bytes::Bytes;
|
||||
use call_contract::{CallContract, RegistryInfo};
|
||||
use ethcore_miner::pool::VerifiedTransaction;
|
||||
use ethcore_miner::service_transaction_checker::ServiceTransactionChecker;
|
||||
use ethereum_types::{H256, Address, U256};
|
||||
use evm::Schedule;
|
||||
use hash::keccak;
|
||||
@@ -45,7 +44,7 @@ use types::receipt::{Receipt, LocalizedReceipt};
|
||||
use types::{BlockNumber, header::{Header, ExtendedHeader}};
|
||||
use vm::{EnvInfo, LastHashes};
|
||||
|
||||
use block::{IsBlock, LockedBlock, Drain, ClosedBlock, OpenBlock, enact_verified, SealedBlock};
|
||||
use block::{LockedBlock, Drain, ClosedBlock, OpenBlock, enact_verified, SealedBlock};
|
||||
use client::ancient_import::AncientVerifier;
|
||||
use client::{
|
||||
Nonce, Balance, ChainInfo, BlockInfo, TransactionInfo,
|
||||
@@ -61,7 +60,7 @@ use client::{
|
||||
IoClient, BadBlocks,
|
||||
};
|
||||
use client::bad_blocks;
|
||||
use engines::{EthEngine, EpochTransition, ForkChoice, EngineError};
|
||||
use engines::{MAX_UNCLE_AGE, EthEngine, EpochTransition, ForkChoice, EngineError};
|
||||
use engines::epoch::PendingTransition;
|
||||
use error::{
|
||||
ImportErrorKind, ExecutionError, CallError, BlockError,
|
||||
@@ -298,19 +297,11 @@ impl Importer {
|
||||
|
||||
match self.check_and_lock_block(&bytes, block, client) {
|
||||
Ok((closed_block, pending)) => {
|
||||
if self.engine.is_proposal(&header) {
|
||||
self.block_queue.mark_as_good(&[hash]);
|
||||
proposed_blocks.push(bytes);
|
||||
} else {
|
||||
imported_blocks.push(hash);
|
||||
|
||||
let transactions_len = closed_block.transactions().len();
|
||||
|
||||
let route = self.commit_block(closed_block, &header, encoded::Block::new(bytes), pending, client);
|
||||
import_results.push(route);
|
||||
|
||||
client.report.write().accrue_block(&header, transactions_len);
|
||||
}
|
||||
imported_blocks.push(hash);
|
||||
let transactions_len = closed_block.transactions.len();
|
||||
let route = self.commit_block(closed_block, &header, encoded::Block::new(bytes), pending, client);
|
||||
import_results.push(route);
|
||||
client.report.write().accrue_block(&header, transactions_len);
|
||||
},
|
||||
Err(err) => {
|
||||
self.bad_blocks.report(bytes, format!("{:?}", err));
|
||||
@@ -407,6 +398,7 @@ impl Importer {
|
||||
let db = client.state_db.read().boxed_clone_canon(header.parent_hash());
|
||||
|
||||
let is_epoch_begin = chain.epoch_transition(parent.number(), *header.parent_hash()).is_some();
|
||||
|
||||
let enact_result = enact_verified(
|
||||
block,
|
||||
engine,
|
||||
@@ -431,13 +423,13 @@ impl Importer {
|
||||
// if the expected receipts root header does not match.
|
||||
// (i.e. allow inconsistency in receipts outcome before the transition block)
|
||||
if header.number() < engine.params().validate_receipts_transition
|
||||
&& header.receipts_root() != locked_block.block().header().receipts_root()
|
||||
&& header.receipts_root() != locked_block.header.receipts_root()
|
||||
{
|
||||
locked_block.strip_receipts_outcomes();
|
||||
}
|
||||
|
||||
// Final Verification
|
||||
if let Err(e) = self.verifier.verify_block_final(&header, locked_block.block().header()) {
|
||||
if let Err(e) = self.verifier.verify_block_final(&header, &locked_block.header) {
|
||||
warn!(target: "client", "Stage 5 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
||||
bail!(e);
|
||||
}
|
||||
@@ -445,8 +437,8 @@ impl Importer {
|
||||
let pending = self.check_epoch_end_signal(
|
||||
&header,
|
||||
bytes,
|
||||
locked_block.receipts(),
|
||||
locked_block.state().db(),
|
||||
&locked_block.receipts,
|
||||
locked_block.state.db(),
|
||||
client
|
||||
)?;
|
||||
|
||||
@@ -1149,7 +1141,7 @@ impl Client {
|
||||
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(snapshot::Error::InvalidStartingBlock(at))?;
|
||||
let block_number = self.block_number(at).ok_or_else(|| snapshot::Error::InvalidStartingBlock(at))?;
|
||||
|
||||
if db.is_pruned() && self.pruning_info().earliest_state > block_number {
|
||||
return Err(snapshot::Error::OldBlockPrunedDB.into());
|
||||
@@ -1578,22 +1570,27 @@ impl Call for Client {
|
||||
let schedule = machine.schedule(env_info.number);
|
||||
Executive::new(&mut clone, &env_info, &machine, &schedule)
|
||||
.transact_virtual(&tx, options())
|
||||
.ok()
|
||||
.map(|r| r.exception.is_none())
|
||||
};
|
||||
|
||||
let cond = |gas| exec(gas).unwrap_or(false);
|
||||
let cond = |gas| {
|
||||
exec(gas)
|
||||
.ok()
|
||||
.map_or(false, |r| r.exception.is_none())
|
||||
};
|
||||
|
||||
if !cond(upper) {
|
||||
upper = max_upper;
|
||||
match exec(upper) {
|
||||
Some(false) => return Err(CallError::Exceptional),
|
||||
None => {
|
||||
Ok(v) => {
|
||||
if let Some(exception) = v.exception {
|
||||
return Err(CallError::Exceptional(exception))
|
||||
}
|
||||
},
|
||||
Err(_e) => {
|
||||
trace!(target: "estimate_gas", "estimate_gas failed with {}", upper);
|
||||
let err = ExecutionError::Internal(format!("Requires higher than upper limit of {}", upper));
|
||||
return Err(err.into())
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
let lower = t.gas_required(&self.engine.schedule(env_info.number)).into();
|
||||
@@ -1706,15 +1703,17 @@ impl BlockChainClient for Client {
|
||||
self.config.spec_name.clone()
|
||||
}
|
||||
|
||||
fn set_spec_name(&self, new_spec_name: String) {
|
||||
fn set_spec_name(&self, new_spec_name: String) -> Result<(), ()> {
|
||||
trace!(target: "mode", "Client::set_spec_name({:?})", new_spec_name);
|
||||
if !self.enabled.load(AtomicOrdering::Relaxed) {
|
||||
return;
|
||||
return Err(());
|
||||
}
|
||||
if let Some(ref h) = *self.exit_handler.lock() {
|
||||
(*h)(new_spec_name);
|
||||
Ok(())
|
||||
} else {
|
||||
warn!("Not hypervised; cannot change chain.");
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1924,7 +1923,7 @@ impl BlockChainClient for Client {
|
||||
}
|
||||
|
||||
fn find_uncles(&self, hash: &H256) -> Option<Vec<H256>> {
|
||||
self.chain.read().find_uncle_hashes(hash, self.engine.maximum_uncle_age())
|
||||
self.chain.read().find_uncle_hashes(hash, MAX_UNCLE_AGE)
|
||||
}
|
||||
|
||||
fn state_data(&self, hash: &H256) -> Option<Bytes> {
|
||||
@@ -2157,10 +2156,14 @@ impl BlockChainClient for Client {
|
||||
|
||||
fn transact_contract(&self, address: Address, data: Bytes) -> Result<(), transaction::Error> {
|
||||
let authoring_params = self.importer.miner.authoring_params();
|
||||
let service_transaction_checker = ServiceTransactionChecker::default();
|
||||
let gas_price = match service_transaction_checker.check_address(self, authoring_params.author) {
|
||||
Ok(true) => U256::zero(),
|
||||
_ => self.importer.miner.sensible_gas_price(),
|
||||
let service_transaction_checker = self.importer.miner.service_transaction_checker();
|
||||
let gas_price = if let Some(checker) = service_transaction_checker {
|
||||
match checker.check_address(self, authoring_params.author) {
|
||||
Ok(true) => U256::zero(),
|
||||
_ => self.importer.miner.sensible_gas_price(),
|
||||
}
|
||||
} else {
|
||||
self.importer.miner.sensible_gas_price()
|
||||
};
|
||||
let transaction = transaction::Transaction {
|
||||
nonce: self.latest_nonce(&authoring_params.author),
|
||||
@@ -2282,24 +2285,24 @@ impl ReopenBlock for Client {
|
||||
fn reopen_block(&self, block: ClosedBlock) -> OpenBlock {
|
||||
let engine = &*self.engine;
|
||||
let mut block = block.reopen(engine);
|
||||
let max_uncles = engine.maximum_uncle_count(block.header().number());
|
||||
if block.uncles().len() < max_uncles {
|
||||
let max_uncles = engine.maximum_uncle_count(block.header.number());
|
||||
if block.uncles.len() < max_uncles {
|
||||
let chain = self.chain.read();
|
||||
let h = chain.best_block_hash();
|
||||
// Add new uncles
|
||||
let uncles = chain
|
||||
.find_uncle_hashes(&h, engine.maximum_uncle_age())
|
||||
.find_uncle_hashes(&h, MAX_UNCLE_AGE)
|
||||
.unwrap_or_else(Vec::new);
|
||||
|
||||
for h in uncles {
|
||||
if !block.uncles().iter().any(|header| header.hash() == h) {
|
||||
if !block.uncles.iter().any(|header| header.hash() == h) {
|
||||
let uncle = chain.block_header_data(&h).expect("find_uncle_hashes only returns hashes for existing headers; qed");
|
||||
let uncle = uncle.decode().expect("decoding failure");
|
||||
block.push_uncle(uncle).expect("pushing up to maximum_uncle_count;
|
||||
push_uncle is not ok only if more than maximum_uncle_count is pushed;
|
||||
so all push_uncle are Ok;
|
||||
qed");
|
||||
if block.uncles().len() >= max_uncles { break }
|
||||
if block.uncles.len() >= max_uncles { break }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2327,15 +2330,15 @@ impl PrepareOpenBlock for Client {
|
||||
gas_range_target,
|
||||
extra_data,
|
||||
is_epoch_begin,
|
||||
&mut chain.ancestry_with_metadata_iter(best_header.hash()),
|
||||
chain.ancestry_with_metadata_iter(best_header.hash()),
|
||||
)?;
|
||||
|
||||
// Add uncles
|
||||
chain
|
||||
.find_uncle_headers(&h, engine.maximum_uncle_age())
|
||||
.find_uncle_headers(&h, MAX_UNCLE_AGE)
|
||||
.unwrap_or_else(Vec::new)
|
||||
.into_iter()
|
||||
.take(engine.maximum_uncle_count(open_block.header().number()))
|
||||
.take(engine.maximum_uncle_count(open_block.header.number()))
|
||||
.foreach(|h| {
|
||||
open_block.push_uncle(h.decode().expect("decoding failure")).expect("pushing maximum_uncle_count;
|
||||
open_block was just created;
|
||||
@@ -2360,7 +2363,7 @@ impl ImportSealedBlock for Client {
|
||||
fn import_sealed_block(&self, block: SealedBlock) -> EthcoreResult<H256> {
|
||||
let start = Instant::now();
|
||||
let raw = block.rlp_bytes();
|
||||
let header = block.header().clone();
|
||||
let header = block.header.clone();
|
||||
let hash = header.hash();
|
||||
self.notify(|n| n.block_pre_import(&raw, &hash, header.difficulty()));
|
||||
|
||||
@@ -2383,8 +2386,8 @@ impl ImportSealedBlock for Client {
|
||||
let pending = self.importer.check_epoch_end_signal(
|
||||
&header,
|
||||
&block_data,
|
||||
block.receipts(),
|
||||
block.state().db(),
|
||||
&block.receipts,
|
||||
block.state.db(),
|
||||
self
|
||||
)?;
|
||||
let route = self.importer.commit_block(
|
||||
@@ -2521,7 +2524,11 @@ impl SnapshotClient for Client {}
|
||||
|
||||
impl Drop for Client {
|
||||
fn drop(&mut self) {
|
||||
self.engine.stop();
|
||||
if let Some(c) = Arc::get_mut(&mut self.engine) {
|
||||
c.stop()
|
||||
} else {
|
||||
warn!(target: "shutdown", "unable to get mut ref for engine for shutdown.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -241,16 +241,17 @@ impl<'a> EvmTestClient<'a> {
|
||||
transaction: transaction::SignedTransaction,
|
||||
tracer: T,
|
||||
vm_tracer: V,
|
||||
) -> TransactResult<T::Output, V::Output> {
|
||||
) -> std::result::Result<TransactSuccess<T::Output, V::Output>, TransactErr> {
|
||||
let initial_gas = transaction.gas;
|
||||
// Verify transaction
|
||||
let is_ok = transaction.verify_basic(true, None, false);
|
||||
if let Err(error) = is_ok {
|
||||
return TransactResult::Err {
|
||||
state_root: *self.state.root(),
|
||||
error: error.into(),
|
||||
end_state: (self.dump_state)(&self.state),
|
||||
};
|
||||
return Err(
|
||||
TransactErr{
|
||||
state_root: *self.state.root(),
|
||||
error: error.into(),
|
||||
end_state: (self.dump_state)(&self.state),
|
||||
});
|
||||
}
|
||||
|
||||
// Apply transaction
|
||||
@@ -283,7 +284,7 @@ impl<'a> EvmTestClient<'a> {
|
||||
|
||||
match result {
|
||||
Ok(result) => {
|
||||
TransactResult::Ok {
|
||||
Ok(TransactSuccess {
|
||||
state_root,
|
||||
gas_left: initial_gas - result.receipt.gas_used,
|
||||
outcome: result.receipt.outcome,
|
||||
@@ -298,47 +299,48 @@ impl<'a> EvmTestClient<'a> {
|
||||
},
|
||||
end_state,
|
||||
}
|
||||
},
|
||||
Err(error) => TransactResult::Err {
|
||||
)},
|
||||
Err(error) => Err(TransactErr {
|
||||
state_root,
|
||||
error,
|
||||
end_state,
|
||||
},
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A result of applying transaction to the state.
|
||||
#[derive(Debug)]
|
||||
pub enum TransactResult<T, V> {
|
||||
/// Successful execution
|
||||
Ok {
|
||||
/// State root
|
||||
state_root: H256,
|
||||
/// Amount of gas left
|
||||
gas_left: U256,
|
||||
/// Output
|
||||
output: Vec<u8>,
|
||||
/// Traces
|
||||
trace: Vec<T>,
|
||||
/// VM Traces
|
||||
vm_trace: Option<V>,
|
||||
/// Created contract address (if any)
|
||||
contract_address: Option<H160>,
|
||||
/// Generated logs
|
||||
logs: Vec<log_entry::LogEntry>,
|
||||
/// outcome
|
||||
outcome: receipt::TransactionOutcome,
|
||||
/// end state if needed
|
||||
end_state: Option<pod_state::PodState>,
|
||||
},
|
||||
/// Transaction failed to run
|
||||
Err {
|
||||
/// State root
|
||||
state_root: H256,
|
||||
/// Execution error
|
||||
error: ::error::Error,
|
||||
/// end state if needed
|
||||
end_state: Option<pod_state::PodState>,
|
||||
},
|
||||
/// To be returned inside a std::result::Result::Ok after a successful
|
||||
/// transaction completed.
|
||||
#[allow(dead_code)]
|
||||
pub struct TransactSuccess<T, V> {
|
||||
/// State root
|
||||
pub state_root: H256,
|
||||
/// Amount of gas left
|
||||
pub gas_left: U256,
|
||||
/// Output
|
||||
pub output: Vec<u8>,
|
||||
/// Traces
|
||||
pub trace: Vec<T>,
|
||||
/// VM Traces
|
||||
pub vm_trace: Option<V>,
|
||||
/// Created contract address (if any)
|
||||
pub contract_address: Option<H160>,
|
||||
/// Generated logs
|
||||
pub logs: Vec<log_entry::LogEntry>,
|
||||
/// outcome
|
||||
pub outcome: receipt::TransactionOutcome,
|
||||
/// end state if needed
|
||||
pub end_state: Option<pod_state::PodState>,
|
||||
}
|
||||
|
||||
/// To be returned inside a std::result::Result::Err after a failed
|
||||
/// transaction.
|
||||
#[allow(dead_code)]
|
||||
pub struct TransactErr {
|
||||
/// State root
|
||||
pub state_root: H256,
|
||||
/// Execution error
|
||||
pub error: ::error::Error,
|
||||
/// end state if needed
|
||||
pub end_state: Option<pod_state::PodState>,
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ mod trace;
|
||||
pub use self::client::*;
|
||||
pub use self::config::{Mode, ClientConfig, DatabaseCompactionProfile, BlockChainConfig, VMType};
|
||||
#[cfg(any(test, feature = "test-helpers"))]
|
||||
pub use self::evm_test_client::{EvmTestClient, EvmTestError, TransactResult};
|
||||
pub use self::evm_test_client::{EvmTestClient, EvmTestError, TransactErr, TransactSuccess};
|
||||
pub use self::io_message::ClientIoMessage;
|
||||
#[cfg(any(test, feature = "test-helpers"))]
|
||||
pub use self::test_client::{TestBlockChainClient, EachBlockWith};
|
||||
|
||||
@@ -416,7 +416,7 @@ impl PrepareOpenBlock for TestBlockChainClient {
|
||||
gas_range_target,
|
||||
extra_data,
|
||||
false,
|
||||
&mut Vec::new().into_iter(),
|
||||
None,
|
||||
)?;
|
||||
// TODO [todr] Override timestamp for predictability
|
||||
open_block.set_timestamp(*self.latest_block_timestamp.read());
|
||||
@@ -863,7 +863,7 @@ impl BlockChainClient for TestBlockChainClient {
|
||||
|
||||
fn spec_name(&self) -> String { "foundation".into() }
|
||||
|
||||
fn set_spec_name(&self, _: String) { unimplemented!(); }
|
||||
fn set_spec_name(&self, _: String) -> Result<(), ()> { unimplemented!(); }
|
||||
|
||||
fn disable(&self) { self.disabled.store(true, AtomicOrder::Relaxed); }
|
||||
|
||||
|
||||
@@ -360,7 +360,7 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra
|
||||
fn spec_name(&self) -> String;
|
||||
|
||||
/// Set the chain via a spec name.
|
||||
fn set_spec_name(&self, spec_name: String);
|
||||
fn set_spec_name(&self, spec_name: String) -> Result<(), ()>;
|
||||
|
||||
/// Disable the client from importing blocks. This cannot be undone in this session and indicates
|
||||
/// that a subsystem has reason to believe this executable incapable of syncing the chain.
|
||||
|
||||
@@ -47,6 +47,9 @@ 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.
|
||||
@@ -512,15 +515,19 @@ fn header_expected_seal_fields(header: &Header, empty_steps_transition: u64) ->
|
||||
}
|
||||
|
||||
fn header_step(header: &Header, empty_steps_transition: u64) -> Result<u64, ::rlp::DecoderError> {
|
||||
let expected_seal_fields = header_expected_seal_fields(header, empty_steps_transition);
|
||||
Rlp::new(&header.seal().get(0).expect(
|
||||
&format!("was either checked with verify_block_basic or is genesis; has {} fields; qed (Make sure the spec file has a correct genesis seal)", expected_seal_fields))).as_val()
|
||||
Rlp::new(&header.seal().get(0).unwrap_or_else(||
|
||||
panic!("was either checked with verify_block_basic or is genesis; has {} fields; qed (Make sure the spec
|
||||
file has a correct genesis seal)", header_expected_seal_fields(header, empty_steps_transition))
|
||||
))
|
||||
.as_val()
|
||||
}
|
||||
|
||||
fn header_signature(header: &Header, empty_steps_transition: u64) -> Result<Signature, ::rlp::DecoderError> {
|
||||
let expected_seal_fields = header_expected_seal_fields(header, empty_steps_transition);
|
||||
Rlp::new(&header.seal().get(1).expect(
|
||||
&format!("was checked with verify_block_basic; has {} fields; qed", expected_seal_fields))).as_val::<H520>().map(Into::into)
|
||||
Rlp::new(&header.seal().get(1).unwrap_or_else(||
|
||||
panic!("was checked with verify_block_basic; has {} fields; qed",
|
||||
header_expected_seal_fields(header, empty_steps_transition))
|
||||
))
|
||||
.as_val::<H520>().map(Into::into)
|
||||
}
|
||||
|
||||
// extracts the raw empty steps vec from the header seal. should only be called when there are 3 fields in the seal
|
||||
@@ -570,8 +577,15 @@ fn verify_timestamp(step: &Step, header_step: u64) -> Result<(), BlockError> {
|
||||
// NOTE This error might be returned only in early stage of verification (Stage 1).
|
||||
// Returning it further won't recover the sync process.
|
||||
trace!(target: "engine", "verify_timestamp: block too early");
|
||||
let oob = oob.map(|n| SystemTime::now() + Duration::from_secs(n));
|
||||
Err(BlockError::TemporarilyInvalid(oob).into())
|
||||
|
||||
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 new_oob = OutOfBounds { min, max, found };
|
||||
|
||||
Err(BlockError::TemporarilyInvalid(new_oob).into())
|
||||
},
|
||||
Ok(_) => Ok(()),
|
||||
}
|
||||
@@ -607,6 +621,7 @@ fn combine_proofs(signal_number: BlockNumber, set_proof: &[u8], finality_proof:
|
||||
stream.out()
|
||||
}
|
||||
|
||||
|
||||
fn destructure_proofs(combined: &[u8]) -> Result<(BlockNumber, &[u8], &[u8]), Error> {
|
||||
let rlp = Rlp::new(combined);
|
||||
Ok((
|
||||
@@ -622,7 +637,7 @@ trait AsMillis {
|
||||
|
||||
impl AsMillis for Duration {
|
||||
fn as_millis(&self) -> u64 {
|
||||
self.as_secs()*1_000 + (self.subsec_nanos()/1_000_000) as u64
|
||||
self.as_secs() * 1_000 + (self.subsec_nanos() / 1_000_000) as u64
|
||||
}
|
||||
}
|
||||
|
||||
@@ -934,8 +949,12 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
return BTreeMap::default();
|
||||
}
|
||||
|
||||
let step = header_step(header, self.empty_steps_transition).as_ref().map(ToString::to_string).unwrap_or("".into());
|
||||
let signature = header_signature(header, self.empty_steps_transition).as_ref().map(ToString::to_string).unwrap_or("".into());
|
||||
let step = header_step(header, self.empty_steps_transition).as_ref()
|
||||
.map(ToString::to_string)
|
||||
.unwrap_or_default();
|
||||
let signature = header_signature(header, self.empty_steps_transition).as_ref()
|
||||
.map(ToString::to_string)
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut info = map![
|
||||
"step".into() => step,
|
||||
@@ -1022,7 +1041,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
return Seal::None;
|
||||
}
|
||||
|
||||
let header = block.header();
|
||||
let header = &block.header;
|
||||
let parent_step = header_step(parent, self.empty_steps_transition)
|
||||
.expect("Header has been verified; qed");
|
||||
|
||||
@@ -1068,7 +1087,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
// `EmptyStep(step, parent_hash)` message. If we exceed the maximum amount of `empty_step` rounds we proceed
|
||||
// with the seal.
|
||||
if header.number() >= self.empty_steps_transition &&
|
||||
block.transactions().is_empty() &&
|
||||
block.transactions.is_empty() &&
|
||||
empty_steps.len() < self.maximum_empty_steps {
|
||||
|
||||
if self.step.can_propose.compare_and_swap(true, false, AtomicOrdering::SeqCst) {
|
||||
@@ -1138,7 +1157,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
if self.immediate_transitions || !epoch_begin { return Ok(()) }
|
||||
|
||||
// genesis is never a new block, but might as well check.
|
||||
let header = block.header().clone();
|
||||
let header = block.header.clone();
|
||||
let first = header.number() == 0;
|
||||
|
||||
let mut call = |to, data| {
|
||||
@@ -1158,8 +1177,8 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
/// Apply the block reward on finalisation of the block.
|
||||
fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> {
|
||||
let mut beneficiaries = Vec::new();
|
||||
if block.header().number() >= self.empty_steps_transition {
|
||||
let empty_steps = if block.header().seal().is_empty() {
|
||||
if block.header.number() >= self.empty_steps_transition {
|
||||
let empty_steps = if block.header.seal().is_empty() {
|
||||
// this is a new block, calculate rewards based on the empty steps messages we have accumulated
|
||||
let client = match self.client.read().as_ref().and_then(|weak| weak.upgrade()) {
|
||||
Some(client) => client,
|
||||
@@ -1169,7 +1188,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
},
|
||||
};
|
||||
|
||||
let parent = client.block_header(::client::BlockId::Hash(*block.header().parent_hash()))
|
||||
let parent = client.block_header(::client::BlockId::Hash(*block.header.parent_hash()))
|
||||
.expect("hash is from parent; parent header must exist; qed")
|
||||
.decode()?;
|
||||
|
||||
@@ -1178,7 +1197,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
self.empty_steps(parent_step.into(), current_step.into(), parent.hash())
|
||||
} else {
|
||||
// we're verifying a block, extract empty steps from the seal
|
||||
header_empty_steps(block.header())?
|
||||
header_empty_steps(&block.header)?
|
||||
};
|
||||
|
||||
for empty_step in empty_steps {
|
||||
@@ -1187,11 +1206,11 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
}
|
||||
}
|
||||
|
||||
let author = *block.header().author();
|
||||
let author = *block.header.author();
|
||||
beneficiaries.push((author, RewardKind::Author));
|
||||
|
||||
let rewards: Vec<_> = match self.block_reward_contract {
|
||||
Some(ref c) if block.header().number() >= self.block_reward_contract_transition => {
|
||||
Some(ref c) if block.header.number() >= self.block_reward_contract_transition => {
|
||||
let mut call = super::default_system_or_code_call(&self.machine, block);
|
||||
|
||||
let rewards = c.reward(&beneficiaries, &mut call)?;
|
||||
@@ -1405,8 +1424,10 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
|
||||
let first = chain_head.number() == 0;
|
||||
|
||||
// apply immediate transitions.
|
||||
// Apply transitions that don't require finality and should be enacted immediately (e.g from chain spec)
|
||||
if let Some(change) = self.validators.is_epoch_end(first, chain_head) {
|
||||
info!(target: "engine", "Immediately applying validator set change signalled at block {}", chain_head.number());
|
||||
self.epoch_manager.lock().note_new_epoch();
|
||||
let change = combine_proofs(chain_head.number(), &change, &[]);
|
||||
return Some(change)
|
||||
}
|
||||
@@ -1618,23 +1639,23 @@ mod tests {
|
||||
let db1 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
||||
let db2 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
||||
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
||||
let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap();
|
||||
let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
|
||||
let b1 = b1.close_and_lock().unwrap();
|
||||
let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap();
|
||||
let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
|
||||
let b2 = b2.close_and_lock().unwrap();
|
||||
|
||||
engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
|
||||
if let Seal::Regular(seal) = engine.generate_seal(b1.block(), &genesis_header) {
|
||||
if let Seal::Regular(seal) = engine.generate_seal(&b1, &genesis_header) {
|
||||
assert!(b1.clone().try_seal(engine, seal).is_ok());
|
||||
// Second proposal is forbidden.
|
||||
assert!(engine.generate_seal(b1.block(), &genesis_header) == Seal::None);
|
||||
assert!(engine.generate_seal(&b1, &genesis_header) == Seal::None);
|
||||
}
|
||||
|
||||
engine.set_signer(Box::new((tap, addr2, "2".into())));
|
||||
if let Seal::Regular(seal) = engine.generate_seal(b2.block(), &genesis_header) {
|
||||
if let Seal::Regular(seal) = engine.generate_seal(&b2, &genesis_header) {
|
||||
assert!(b2.clone().try_seal(engine, seal).is_ok());
|
||||
// Second proposal is forbidden.
|
||||
assert!(engine.generate_seal(b2.block(), &genesis_header) == Seal::None);
|
||||
assert!(engine.generate_seal(&b2, &genesis_header) == Seal::None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1652,19 +1673,19 @@ mod tests {
|
||||
let db2 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
||||
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
||||
|
||||
let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap();
|
||||
let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
|
||||
let b1 = b1.close_and_lock().unwrap();
|
||||
let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap();
|
||||
let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
|
||||
let b2 = b2.close_and_lock().unwrap();
|
||||
|
||||
engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
|
||||
match engine.generate_seal(b1.block(), &genesis_header) {
|
||||
match engine.generate_seal(&b1, &genesis_header) {
|
||||
Seal::None | Seal::Proposal(_) => panic!("wrong seal"),
|
||||
Seal::Regular(_) => {
|
||||
engine.step();
|
||||
|
||||
engine.set_signer(Box::new((tap.clone(), addr2, "0".into())));
|
||||
match engine.generate_seal(b2.block(), &genesis_header) {
|
||||
match engine.generate_seal(&b2, &genesis_header) {
|
||||
Seal::Regular(_) | Seal::Proposal(_) => panic!("sealed despite wrong difficulty"),
|
||||
Seal::None => {}
|
||||
}
|
||||
@@ -1888,11 +1909,11 @@ mod tests {
|
||||
|
||||
engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
|
||||
|
||||
let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap();
|
||||
let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
|
||||
let b1 = b1.close_and_lock().unwrap();
|
||||
|
||||
// the block is empty so we don't seal and instead broadcast an empty step message
|
||||
assert_eq!(engine.generate_seal(b1.block(), &genesis_header), Seal::None);
|
||||
assert_eq!(engine.generate_seal(&b1, &genesis_header), Seal::None);
|
||||
|
||||
// spec starts with step 2
|
||||
let empty_step_rlp = encode(&empty_step(engine, 2, &genesis_header.hash()));
|
||||
@@ -1902,7 +1923,7 @@ mod tests {
|
||||
let len = notify.messages.read().len();
|
||||
|
||||
// make sure that we don't generate empty step for the second time
|
||||
assert_eq!(engine.generate_seal(b1.block(), &genesis_header), Seal::None);
|
||||
assert_eq!(engine.generate_seal(&b1, &genesis_header), Seal::None);
|
||||
assert_eq!(len, notify.messages.read().len());
|
||||
}
|
||||
|
||||
@@ -1926,16 +1947,16 @@ mod tests {
|
||||
engine.register_client(Arc::downgrade(&client) as _);
|
||||
|
||||
// step 2
|
||||
let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap();
|
||||
let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
|
||||
let b1 = b1.close_and_lock().unwrap();
|
||||
|
||||
// since the block is empty it isn't sealed and we generate empty steps
|
||||
engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
|
||||
assert_eq!(engine.generate_seal(b1.block(), &genesis_header), Seal::None);
|
||||
assert_eq!(engine.generate_seal(&b1, &genesis_header), Seal::None);
|
||||
engine.step();
|
||||
|
||||
// step 3
|
||||
let mut b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap();
|
||||
let mut b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
|
||||
b2.push_transaction(Transaction {
|
||||
action: Action::Create,
|
||||
nonce: U256::from(0),
|
||||
@@ -1948,7 +1969,7 @@ mod tests {
|
||||
|
||||
// we will now seal a block with 1tx and include the accumulated empty step message
|
||||
engine.set_signer(Box::new((tap.clone(), addr2, "0".into())));
|
||||
if let Seal::Regular(seal) = engine.generate_seal(b2.block(), &genesis_header) {
|
||||
if let Seal::Regular(seal) = engine.generate_seal(&b2, &genesis_header) {
|
||||
engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
|
||||
let empty_step2 = sealed_empty_step(engine, 2, &genesis_header.hash());
|
||||
let empty_steps = ::rlp::encode_list(&vec![empty_step2]);
|
||||
@@ -1979,28 +2000,28 @@ mod tests {
|
||||
engine.register_client(Arc::downgrade(&client) as _);
|
||||
|
||||
// step 2
|
||||
let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap();
|
||||
let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
|
||||
let b1 = b1.close_and_lock().unwrap();
|
||||
|
||||
// since the block is empty it isn't sealed and we generate empty steps
|
||||
engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
|
||||
assert_eq!(engine.generate_seal(b1.block(), &genesis_header), Seal::None);
|
||||
assert_eq!(engine.generate_seal(&b1, &genesis_header), Seal::None);
|
||||
engine.step();
|
||||
|
||||
// step 3
|
||||
let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap();
|
||||
let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
|
||||
let b2 = b2.close_and_lock().unwrap();
|
||||
engine.set_signer(Box::new((tap.clone(), addr2, "0".into())));
|
||||
assert_eq!(engine.generate_seal(b2.block(), &genesis_header), Seal::None);
|
||||
assert_eq!(engine.generate_seal(&b2, &genesis_header), Seal::None);
|
||||
engine.step();
|
||||
|
||||
// step 4
|
||||
// the spec sets the maximum_empty_steps to 2 so we will now seal an empty block and include the empty step messages
|
||||
let b3 = OpenBlock::new(engine, Default::default(), false, db3, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap();
|
||||
let b3 = OpenBlock::new(engine, Default::default(), false, db3, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
|
||||
let b3 = b3.close_and_lock().unwrap();
|
||||
|
||||
engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
|
||||
if let Seal::Regular(seal) = engine.generate_seal(b3.block(), &genesis_header) {
|
||||
if let Seal::Regular(seal) = engine.generate_seal(&b3, &genesis_header) {
|
||||
let empty_step2 = sealed_empty_step(engine, 2, &genesis_header.hash());
|
||||
engine.set_signer(Box::new((tap.clone(), addr2, "0".into())));
|
||||
let empty_step3 = sealed_empty_step(engine, 3, &genesis_header.hash());
|
||||
@@ -2029,24 +2050,24 @@ mod tests {
|
||||
engine.register_client(Arc::downgrade(&client) as _);
|
||||
|
||||
// step 2
|
||||
let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap();
|
||||
let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
|
||||
let b1 = b1.close_and_lock().unwrap();
|
||||
|
||||
// since the block is empty it isn't sealed and we generate empty steps
|
||||
engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
|
||||
assert_eq!(engine.generate_seal(b1.block(), &genesis_header), Seal::None);
|
||||
assert_eq!(engine.generate_seal(&b1, &genesis_header), Seal::None);
|
||||
engine.step();
|
||||
|
||||
// step 3
|
||||
// the signer of the accumulated empty step message should be rewarded
|
||||
let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap();
|
||||
let addr1_balance = b2.block().state().balance(&addr1).unwrap();
|
||||
let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
|
||||
let addr1_balance = b2.state.balance(&addr1).unwrap();
|
||||
|
||||
// after closing the block `addr1` should be reward twice, one for the included empty step message and another for block creation
|
||||
let b2 = b2.close_and_lock().unwrap();
|
||||
|
||||
// the spec sets the block reward to 10
|
||||
assert_eq!(b2.block().state().balance(&addr1).unwrap(), addr1_balance + (10 * 2))
|
||||
assert_eq!(b2.state.balance(&addr1).unwrap(), addr1_balance + (10 * 2))
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -2139,13 +2160,13 @@ mod tests {
|
||||
(3141562.into(), 31415620.into()),
|
||||
vec![],
|
||||
false,
|
||||
&mut Vec::new().into_iter(),
|
||||
None,
|
||||
).unwrap();
|
||||
let b1 = b1.close_and_lock().unwrap();
|
||||
|
||||
// since the block is empty it isn't sealed and we generate empty steps
|
||||
engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
|
||||
assert_eq!(engine.generate_seal(b1.block(), &genesis_header), Seal::None);
|
||||
assert_eq!(engine.generate_seal(&b1, &genesis_header), Seal::None);
|
||||
engine.step();
|
||||
|
||||
// step 3
|
||||
@@ -2161,9 +2182,9 @@ mod tests {
|
||||
(3141562.into(), 31415620.into()),
|
||||
vec![],
|
||||
false,
|
||||
&mut Vec::new().into_iter(),
|
||||
None,
|
||||
).unwrap();
|
||||
let addr1_balance = b2.block().state().balance(&addr1).unwrap();
|
||||
let addr1_balance = b2.state.balance(&addr1).unwrap();
|
||||
|
||||
// after closing the block `addr1` should be reward twice, one for the included empty step
|
||||
// message and another for block creation
|
||||
@@ -2171,7 +2192,7 @@ mod tests {
|
||||
|
||||
// the contract rewards (1000 + kind) for each benefactor/reward kind
|
||||
assert_eq!(
|
||||
b2.block().state().balance(&addr1).unwrap(),
|
||||
b2.state.balance(&addr1).unwrap(),
|
||||
addr1_balance + (1000 + 0) + (1000 + 2),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ impl Engine<EthereumMachine> for BasicAuthority {
|
||||
|
||||
/// Attempt to seal the block internally.
|
||||
fn generate_seal(&self, block: &ExecutedBlock, _parent: &Header) -> Seal {
|
||||
let header = block.header();
|
||||
let header = &block.header;
|
||||
let author = header.author();
|
||||
if self.validators.contains(header.parent_hash(), author) {
|
||||
// account should be pernamently unlocked, otherwise sealing will fail
|
||||
@@ -264,9 +264,9 @@ mod tests {
|
||||
let genesis_header = spec.genesis_header();
|
||||
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
||||
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
||||
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap();
|
||||
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
|
||||
let b = b.close_and_lock().unwrap();
|
||||
if let Seal::Regular(seal) = engine.generate_seal(b.block(), &genesis_header) {
|
||||
if let Seal::Regular(seal) = engine.generate_seal(&b, &genesis_header) {
|
||||
assert!(b.try_seal(engine, seal).is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,11 +24,12 @@ use ethereum_types::{H160, Address, U256};
|
||||
use std::sync::Arc;
|
||||
use hash::keccak;
|
||||
use error::Error;
|
||||
use machine::WithRewards;
|
||||
use parity_machine::Machine;
|
||||
use machine::Machine;
|
||||
use trace;
|
||||
use types::BlockNumber;
|
||||
use super::{SystemOrCodeCall, SystemOrCodeCallKind};
|
||||
use trace::{Tracer, ExecutiveTracer, Tracing};
|
||||
use block::ExecutedBlock;
|
||||
|
||||
use_contract!(block_reward_contract, "res/contracts/block_reward.json");
|
||||
|
||||
@@ -152,17 +153,26 @@ impl BlockRewardContract {
|
||||
|
||||
/// Applies the given block rewards, i.e. adds the given balance to each beneficiary' address.
|
||||
/// If tracing is enabled the operations are recorded.
|
||||
pub fn apply_block_rewards<M: Machine + WithRewards>(
|
||||
pub fn apply_block_rewards<M: Machine>(
|
||||
rewards: &[(Address, RewardKind, U256)],
|
||||
block: &mut M::LiveBlock,
|
||||
block: &mut ExecutedBlock,
|
||||
machine: &M,
|
||||
) -> Result<(), M::Error> {
|
||||
for &(ref author, _, ref block_reward) in rewards {
|
||||
machine.add_balance(block, author, block_reward)?;
|
||||
}
|
||||
|
||||
let rewards: Vec<_> = rewards.into_iter().map(|&(a, k, r)| (a, k.into(), r)).collect();
|
||||
machine.note_rewards(block, &rewards)
|
||||
if let Tracing::Enabled(ref mut traces) = *block.traces_mut() {
|
||||
let mut tracer = ExecutiveTracer::default();
|
||||
|
||||
for &(address, reward_kind, amount) in rewards {
|
||||
tracer.trace_reward(address, amount, reward_kind.into());
|
||||
}
|
||||
|
||||
traces.push(tracer.drain().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
369
ethcore/src/engines/clique/block_state.rs
Normal file
369
ethcore/src/engines/clique/block_state.rs
Normal file
@@ -0,0 +1,369 @@
|
||||
// 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/>.
|
||||
|
||||
use std::collections::{HashMap, BTreeSet, VecDeque};
|
||||
use std::fmt;
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
|
||||
use engines::EngineError;
|
||||
use engines::clique::util::{extract_signers, recover_creator};
|
||||
use engines::clique::{VoteType, DIFF_INTURN, DIFF_NOTURN, NULL_AUTHOR, SIGNING_DELAY_NOTURN_MS};
|
||||
use error::{Error, BlockError};
|
||||
use ethereum_types::{Address, H64};
|
||||
use rand::Rng;
|
||||
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)]
|
||||
pub struct VoteState {
|
||||
kind: VoteType,
|
||||
votes: u64,
|
||||
}
|
||||
|
||||
/// Type that represent a vote
|
||||
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub struct Vote {
|
||||
block_number: BlockNumber,
|
||||
beneficiary: Address,
|
||||
kind: VoteType,
|
||||
signer: Address,
|
||||
reverted: bool,
|
||||
}
|
||||
|
||||
/// Type that represent a pending vote
|
||||
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd)]
|
||||
pub struct PendingVote {
|
||||
signer: Address,
|
||||
beneficiary: Address,
|
||||
}
|
||||
|
||||
/// Clique state for each block.
|
||||
#[cfg(not(test))]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct CliqueBlockState {
|
||||
/// Current votes for a beneficiary
|
||||
votes: HashMap<PendingVote, VoteState>,
|
||||
/// A list of all votes for the given epoch
|
||||
votes_history: Vec<Vote>,
|
||||
/// a list of all valid signer, sorted by ascending order.
|
||||
signers: BTreeSet<Address>,
|
||||
/// a deque of recent signer, new entry should be pushed front, apply() modifies this.
|
||||
recent_signers: VecDeque<Address>,
|
||||
/// inturn signing should wait until this time
|
||||
pub next_timestamp_inturn: Option<SystemTime>,
|
||||
/// noturn signing should wait until this time
|
||||
pub next_timestamp_noturn: Option<SystemTime>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct CliqueBlockState {
|
||||
/// All recorded votes for a given signer, `Vec<PendingVote>` is a stack of votes
|
||||
pub votes: HashMap<PendingVote, VoteState>,
|
||||
/// A list of all votes for the given epoch
|
||||
pub votes_history: Vec<Vote>,
|
||||
/// a list of all valid signer, sorted by ascending order.
|
||||
pub signers: BTreeSet<Address>,
|
||||
/// a deque of recent signer, new entry should be pushed front, apply() modifies this.
|
||||
pub recent_signers: VecDeque<Address>,
|
||||
/// inturn signing should wait until this time
|
||||
pub next_timestamp_inturn: Option<SystemTime>,
|
||||
/// noturn signing should wait until this time
|
||||
pub next_timestamp_noturn: Option<SystemTime>,
|
||||
}
|
||||
|
||||
impl fmt::Display for CliqueBlockState {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let signers: Vec<String> = self.signers.iter()
|
||||
.map(|s|
|
||||
format!("{} {:?}",
|
||||
s,
|
||||
self.votes.iter().map(|(v, s)| format!("[beneficiary {}, votes: {}]", v.beneficiary, s.votes))
|
||||
.collect::<Vec<_>>()
|
||||
)
|
||||
)
|
||||
.collect();
|
||||
|
||||
let recent_signers: Vec<String> = self.recent_signers.iter().map(|s| format!("{}", s)).collect();
|
||||
let num_votes = self.votes_history.len();
|
||||
let add_votes = self.votes_history.iter().filter(|v| v.kind == VoteType::Add).count();
|
||||
let rm_votes = self.votes_history.iter().filter(|v| v.kind == VoteType::Remove).count();
|
||||
let reverted_votes = self.votes_history.iter().filter(|v| v.reverted).count();
|
||||
|
||||
write!(f,
|
||||
"Votes {{ \n signers: {:?} \n recent_signers: {:?} \n number of votes: {} \n number of add votes {}
|
||||
\r number of remove votes {} \n number of reverted votes: {}}}",
|
||||
signers, recent_signers, num_votes, add_votes, rm_votes, reverted_votes)
|
||||
}
|
||||
}
|
||||
|
||||
impl CliqueBlockState {
|
||||
/// Create new state with given information, this is used creating new state from Checkpoint block.
|
||||
pub fn new(signers: BTreeSet<Address>) -> Self {
|
||||
CliqueBlockState {
|
||||
signers,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
// see https://github.com/ethereum/go-ethereum/blob/master/consensus/clique/clique.go#L474
|
||||
fn verify(&self, header: &Header) -> Result<Address, Error> {
|
||||
let creator = recover_creator(header)?.clone();
|
||||
|
||||
// The signer is not authorized
|
||||
if !self.signers.contains(&creator) {
|
||||
trace!(target: "engine", "current state: {}", self);
|
||||
Err(EngineError::NotAuthorized(creator))?
|
||||
}
|
||||
|
||||
// The signer has signed a block too recently
|
||||
if self.recent_signers.contains(&creator) {
|
||||
trace!(target: "engine", "current state: {}", self);
|
||||
Err(EngineError::CliqueTooRecentlySigned(creator))?
|
||||
}
|
||||
|
||||
// Wrong difficulty
|
||||
let inturn = self.is_inturn(header.number(), &creator);
|
||||
|
||||
if inturn && *header.difficulty() != DIFF_INTURN {
|
||||
Err(BlockError::InvalidDifficulty(Mismatch {
|
||||
expected: DIFF_INTURN,
|
||||
found: *header.difficulty(),
|
||||
}))?
|
||||
}
|
||||
|
||||
if !inturn && *header.difficulty() != DIFF_NOTURN {
|
||||
Err(BlockError::InvalidDifficulty(Mismatch {
|
||||
expected: DIFF_NOTURN,
|
||||
found: *header.difficulty(),
|
||||
}))?
|
||||
}
|
||||
|
||||
Ok(creator)
|
||||
}
|
||||
|
||||
/// Verify and apply a new header to current state
|
||||
pub fn apply(&mut self, header: &Header, is_checkpoint: bool) -> Result<Address, Error> {
|
||||
let creator = self.verify(header)?;
|
||||
self.recent_signers.push_front(creator);
|
||||
self.rotate_recent_signers();
|
||||
|
||||
if is_checkpoint {
|
||||
// checkpoint block should not affect previous tallying, so we check that.
|
||||
let signers = extract_signers(header)?;
|
||||
if self.signers != signers {
|
||||
let invalid_signers: Vec<String> = signers.into_iter()
|
||||
.filter(|s| !self.signers.contains(s))
|
||||
.map(|s| format!("{}", s))
|
||||
.collect();
|
||||
Err(EngineError::CliqueFaultyRecoveredSigners(invalid_signers))?
|
||||
};
|
||||
|
||||
// TODO(niklasad1): I'm not sure if we should shrink here because it is likely that next epoch
|
||||
// will need some memory and might be better for allocation algorithm to decide whether to shrink or not
|
||||
// (typically doubles or halves the allocted memory when necessary)
|
||||
self.votes.clear();
|
||||
self.votes_history.clear();
|
||||
self.votes.shrink_to_fit();
|
||||
self.votes_history.shrink_to_fit();
|
||||
}
|
||||
|
||||
// Contains vote
|
||||
if *header.author() != NULL_AUTHOR {
|
||||
let decoded_seal = header.decode_seal::<Vec<_>>()?;
|
||||
if decoded_seal.len() != 2 {
|
||||
Err(BlockError::InvalidSealArity(Mismatch { expected: 2, found: decoded_seal.len() }))?
|
||||
}
|
||||
|
||||
let nonce: H64 = decoded_seal[1].into();
|
||||
self.update_signers_on_vote(VoteType::from_nonce(nonce)?, creator, *header.author(), header.number())?;
|
||||
}
|
||||
|
||||
Ok(creator)
|
||||
}
|
||||
|
||||
fn update_signers_on_vote(
|
||||
&mut self,
|
||||
kind: VoteType,
|
||||
signer: Address,
|
||||
beneficiary: Address,
|
||||
block_number: u64
|
||||
) -> Result<(), Error> {
|
||||
|
||||
trace!(target: "engine", "Attempt vote {:?} {:?}", kind, beneficiary);
|
||||
|
||||
let pending_vote = PendingVote { signer, beneficiary };
|
||||
|
||||
let reverted = if self.is_valid_vote(&beneficiary, kind) {
|
||||
self.add_vote(pending_vote, kind)
|
||||
} else {
|
||||
// This case only happens if a `signer` wants to revert their previous vote
|
||||
// (does nothing if no previous vote was found)
|
||||
self.revert_vote(pending_vote)
|
||||
};
|
||||
|
||||
// Add all votes to the history
|
||||
self.votes_history.push(
|
||||
Vote {
|
||||
block_number,
|
||||
beneficiary,
|
||||
kind,
|
||||
signer,
|
||||
reverted,
|
||||
});
|
||||
|
||||
// If no vote was found for the beneficiary return `early` but don't propogate an error
|
||||
let (votes, vote_kind) = match self.get_current_votes_and_kind(beneficiary) {
|
||||
Some((v, k)) => (v, k),
|
||||
None => return Ok(()),
|
||||
};
|
||||
let threshold = self.signers.len() / 2;
|
||||
|
||||
debug!(target: "engine", "{}/{} votes to have consensus", votes, threshold + 1);
|
||||
trace!(target: "engine", "votes: {:?}", votes);
|
||||
|
||||
if votes > threshold {
|
||||
match vote_kind {
|
||||
VoteType::Add => {
|
||||
if self.signers.insert(beneficiary) {
|
||||
debug!(target: "engine", "added new signer: {}", beneficiary);
|
||||
}
|
||||
}
|
||||
VoteType::Remove => {
|
||||
if self.signers.remove(&beneficiary) {
|
||||
debug!(target: "engine", "removed signer: {}", beneficiary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.rotate_recent_signers();
|
||||
self.remove_all_votes_from(beneficiary);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Calculate the next timestamp for `inturn` and `noturn` fails if any of them can't be represented as
|
||||
/// `SystemTime`
|
||||
// TODO(niklasad1): refactor this method to be in constructor of `CliqueBlockState` instead.
|
||||
// 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)));
|
||||
|
||||
self.next_timestamp_inturn = inturn;
|
||||
|
||||
let delay = Duration::from_millis(
|
||||
rand::thread_rng().gen_range(0u64, (self.signers.len() as u64 / 2 + 1) * SIGNING_DELAY_NOTURN_MS));
|
||||
self.next_timestamp_noturn = inturn.map(|inturn| {
|
||||
inturn + delay
|
||||
});
|
||||
|
||||
if self.next_timestamp_inturn.is_some() && self.next_timestamp_noturn.is_some() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(BlockError::TimestampOverflow)?
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the block difficulty should be `inturn`
|
||||
pub fn is_inturn(&self, current_block_number: u64, author: &Address) -> bool {
|
||||
if let Some(pos) = self.signers.iter().position(|x| *author == *x) {
|
||||
return current_block_number % self.signers.len() as u64 == pos as u64;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns whether the signer is authorized to sign a block
|
||||
pub fn is_authorized(&self, author: &Address) -> bool {
|
||||
self.signers.contains(author) && !self.recent_signers.contains(author)
|
||||
}
|
||||
|
||||
/// Returns whether it makes sense to cast the specified vote in the
|
||||
/// current state (e.g. don't try to add an already authorized signer).
|
||||
pub fn is_valid_vote(&self, address: &Address, vote_type: VoteType) -> bool {
|
||||
let in_signer = self.signers.contains(address);
|
||||
match vote_type {
|
||||
VoteType::Add => !in_signer,
|
||||
VoteType::Remove => in_signer,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the list of current signers
|
||||
pub fn signers(&self) -> &BTreeSet<Address> {
|
||||
&self.signers
|
||||
}
|
||||
|
||||
// Note this method will always return `true` but it is intended for a uniform `API`
|
||||
fn add_vote(&mut self, pending_vote: PendingVote, kind: VoteType) -> bool {
|
||||
|
||||
self.votes.entry(pending_vote)
|
||||
.and_modify(|state| {
|
||||
state.votes = state.votes.saturating_add(1);
|
||||
})
|
||||
.or_insert_with(|| VoteState { kind, votes: 1 });
|
||||
true
|
||||
}
|
||||
|
||||
fn revert_vote(&mut self, pending_vote: PendingVote) -> bool {
|
||||
let mut revert = false;
|
||||
let mut remove = false;
|
||||
|
||||
self.votes.entry(pending_vote).and_modify(|state| {
|
||||
if state.votes.saturating_sub(1) == 0 {
|
||||
remove = true;
|
||||
}
|
||||
revert = true;
|
||||
});
|
||||
|
||||
if remove {
|
||||
self.votes.remove(&pending_vote);
|
||||
}
|
||||
|
||||
revert
|
||||
}
|
||||
|
||||
fn get_current_votes_and_kind(&self, beneficiary: Address) -> Option<(usize, VoteType)> {
|
||||
let kind = self.votes.iter()
|
||||
.find(|(v, _t)| v.beneficiary == beneficiary)
|
||||
.map(|(_v, t)| t.kind)?;
|
||||
|
||||
let votes = self.votes.keys()
|
||||
.filter(|vote| vote.beneficiary == beneficiary)
|
||||
.count();
|
||||
|
||||
Some((votes, kind))
|
||||
}
|
||||
|
||||
fn rotate_recent_signers(&mut self) {
|
||||
if self.recent_signers.len() >= ( self.signers.len() / 2 ) + 1 {
|
||||
self.recent_signers.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_all_votes_from(&mut self, beneficiary: Address) {
|
||||
self.votes = std::mem::replace(&mut self.votes, HashMap::new())
|
||||
.into_iter()
|
||||
.filter(|(v, _t)| v.signer != beneficiary && v.beneficiary != beneficiary)
|
||||
.collect();
|
||||
}
|
||||
}
|
||||
776
ethcore/src/engines/clique/mod.rs
Normal file
776
ethcore/src/engines/clique/mod.rs
Normal file
@@ -0,0 +1,776 @@
|
||||
// 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/>.
|
||||
|
||||
//! Implementation of the Clique PoA Engine.
|
||||
//!
|
||||
//! File structure:
|
||||
//! - mod.rs -> Provides the engine API implementation, with additional block state tracking
|
||||
//! - block_state.rs -> Records the Clique state for given block.
|
||||
//! - params.rs -> Contains the parameters for the Clique engine.
|
||||
//! - step_service.rs -> An event loop to trigger sealing.
|
||||
//! - util.rs -> Various standalone utility functions.
|
||||
//! - tests.rs -> Consensus tests as defined in EIP-225.
|
||||
|
||||
/// How syncing works:
|
||||
///
|
||||
/// 1. Client will call:
|
||||
/// - `Clique::verify_block_basic()`
|
||||
/// - `Clique::verify_block_unordered()`
|
||||
/// - `Clique::verify_block_family()`
|
||||
/// 2. Using `Clique::state()` we try and retrieve the parent state. If this isn't found
|
||||
/// we need to back-fill it from the last known checkpoint.
|
||||
/// 3. Once we have a good state, we can record it using `CliqueBlockState::apply()`.
|
||||
|
||||
/// How sealing works:
|
||||
///
|
||||
/// 1. Set a signer using `Engine::set_signer()`. If a miner account was set up through
|
||||
/// a config file or CLI flag `MinerService::set_author()` will eventually set the signer
|
||||
/// 2. We check that the engine seals internally through `Clique::seals_internally()`
|
||||
/// Note: This is always true for Clique
|
||||
/// 3. Calling `Clique::new()` will spawn a `StepService` thread. This thread will call `Engine::step()`
|
||||
/// periodically. Internally, the Clique `step()` function calls `Client::update_sealing()`, which is
|
||||
/// what makes and seals a block.
|
||||
/// 4. `Clique::generate_seal()` will then be called by `miner`. This will return a `Seal` which
|
||||
/// is either a `Seal::None` or `Seal:Regular`. The following shows how a `Seal` variant is chosen:
|
||||
/// a. We return `Seal::None` if no signer is available or the signer is not authorized.
|
||||
/// b. If period == 0 and block has transactions, we return `Seal::Regular`, otherwise return `Seal::None`.
|
||||
/// c. If we're `INTURN`, wait for at least `period` since last block before trying to seal.
|
||||
/// d. If we're not `INTURN`, we wait for a random amount of time using the algorithm specified
|
||||
/// in EIP-225 before trying to seal again.
|
||||
/// 5. Miner will create new block, in process it will call several engine methods to do following:
|
||||
/// a. `Clique::open_block_header_timestamp()` must set timestamp correctly.
|
||||
/// b. `Clique::populate_from_parent()` must set difficulty to correct value.
|
||||
/// Note: `Clique::populate_from_parent()` is used in both the syncing and sealing code paths.
|
||||
/// 6. We call `Clique::on_seal_block()` which will allow us to modify the block header during seal generation.
|
||||
/// 7. Finally, `Clique::verify_local_seal()` is called. After this, the syncing code path will be followed
|
||||
/// in order to import the new block.
|
||||
|
||||
use std::cmp;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::VecDeque;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::thread;
|
||||
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};
|
||||
use error::{BlockError, Error};
|
||||
use ethereum_types::{Address, H64, H160, H256, U256};
|
||||
use ethkey::Signature;
|
||||
use hash::KECCAK_EMPTY_LIST_RLP;
|
||||
use itertools::Itertools;
|
||||
use lru_cache::LruCache;
|
||||
use machine::{Call, EthereumMachine};
|
||||
use parking_lot::RwLock;
|
||||
use rand::Rng;
|
||||
use super::signer::EngineSigner;
|
||||
use unexpected::{Mismatch, OutOfBounds};
|
||||
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;
|
||||
|
||||
mod params;
|
||||
mod block_state;
|
||||
mod step_service;
|
||||
mod util;
|
||||
|
||||
// TODO(niklasad1): extract tester types into a separate mod to be shared in the code base
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
// Protocol constants
|
||||
/// Fixed number of extra-data prefix bytes reserved for signer vanity
|
||||
pub const VANITY_LENGTH: usize = 32;
|
||||
/// Fixed number of extra-data suffix bytes reserved for signer signature
|
||||
pub const SIGNATURE_LENGTH: usize = 65;
|
||||
/// Address length of signer
|
||||
pub const ADDRESS_LENGTH: usize = 20;
|
||||
/// Nonce value for DROP vote
|
||||
pub const NONCE_DROP_VOTE: H64 = H64([0; 8]);
|
||||
/// Nonce value for AUTH vote
|
||||
pub const NONCE_AUTH_VOTE: H64 = H64([0xff; 8]);
|
||||
/// Difficulty for INTURN block
|
||||
pub const DIFF_INTURN: U256 = U256([2, 0, 0, 0]);
|
||||
/// Difficulty for NOTURN block
|
||||
pub const DIFF_NOTURN: U256 = U256([1, 0, 0, 0]);
|
||||
/// Default empty author field value
|
||||
pub const NULL_AUTHOR: Address = H160([0x00; 20]);
|
||||
/// Default empty nonce value
|
||||
pub const NULL_NONCE: H64 = NONCE_DROP_VOTE;
|
||||
/// Default value for mixhash
|
||||
pub const NULL_MIXHASH: H256 = H256([0; 32]);
|
||||
/// Default value for uncles hash
|
||||
pub const NULL_UNCLES_HASH: H256 = KECCAK_EMPTY_LIST_RLP;
|
||||
/// Default noturn block wiggle factor defined in spec.
|
||||
pub const SIGNING_DELAY_NOTURN_MS: u64 = 500;
|
||||
|
||||
/// How many CliqueBlockState to cache in the memory.
|
||||
pub const STATE_CACHE_NUM: usize = 128;
|
||||
|
||||
/// Vote to add or remove the beneficiary
|
||||
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub enum VoteType {
|
||||
Add,
|
||||
Remove,
|
||||
}
|
||||
|
||||
impl VoteType {
|
||||
/// Try to construct a `Vote` from a nonce
|
||||
pub fn from_nonce(nonce: H64) -> Result<Self, Error> {
|
||||
if nonce == NONCE_AUTH_VOTE {
|
||||
Ok(VoteType::Add)
|
||||
} else if nonce == NONCE_DROP_VOTE {
|
||||
Ok(VoteType::Remove)
|
||||
} else {
|
||||
Err(EngineError::CliqueInvalidNonce(nonce))?
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the rlp encoding of the vote
|
||||
pub fn as_rlp(&self) -> Vec<Vec<u8>> {
|
||||
match self {
|
||||
VoteType::Add => vec![rlp::encode(&NULL_MIXHASH), rlp::encode(&NONCE_AUTH_VOTE)],
|
||||
VoteType::Remove => vec![rlp::encode(&NULL_MIXHASH), rlp::encode(&NONCE_DROP_VOTE)],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Clique Engine implementation
|
||||
// block_state_by_hash -> block state indexed by header hash.
|
||||
#[cfg(not(test))]
|
||||
pub struct Clique {
|
||||
epoch_length: u64,
|
||||
period: u64,
|
||||
machine: EthereumMachine,
|
||||
client: RwLock<Option<Weak<EngineClient>>>,
|
||||
block_state_by_hash: RwLock<LruCache<H256, CliqueBlockState>>,
|
||||
proposals: RwLock<HashMap<Address, VoteType>>,
|
||||
signer: RwLock<Option<Box<EngineSigner>>>,
|
||||
step_service: Option<Arc<StepService>>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
/// Test version of `CliqueEngine` to make all fields public
|
||||
pub struct Clique {
|
||||
pub epoch_length: u64,
|
||||
pub period: u64,
|
||||
pub machine: EthereumMachine,
|
||||
pub client: RwLock<Option<Weak<EngineClient>>>,
|
||||
pub block_state_by_hash: RwLock<LruCache<H256, CliqueBlockState>>,
|
||||
pub proposals: RwLock<HashMap<Address, VoteType>>,
|
||||
pub signer: RwLock<Option<Box<EngineSigner>>>,
|
||||
pub step_service: Option<Arc<StepService>>,
|
||||
}
|
||||
|
||||
impl Clique {
|
||||
/// Initialize Clique engine from empty state.
|
||||
pub fn new(our_params: CliqueParams, machine: EthereumMachine) -> Result<Arc<Self>, Error> {
|
||||
let mut engine = Clique {
|
||||
epoch_length: our_params.epoch,
|
||||
period: our_params.period,
|
||||
client: Default::default(),
|
||||
block_state_by_hash: RwLock::new(LruCache::new(STATE_CACHE_NUM)),
|
||||
proposals: Default::default(),
|
||||
signer: Default::default(),
|
||||
machine,
|
||||
step_service: None,
|
||||
};
|
||||
|
||||
let res = Arc::new(engine);
|
||||
|
||||
if our_params.period > 0 {
|
||||
engine.step_service = Some(StepService::start(Arc::downgrade(&res) as Weak<Engine<_>>));
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
/// Initialize test variant of `CliqueEngine`,
|
||||
/// Note we need to `mock` the miner and it is introduced to test block verification to trigger new blocks
|
||||
/// to mainly test consensus edge cases
|
||||
pub fn with_test(epoch_length: u64, period: u64) -> Self {
|
||||
use spec::Spec;
|
||||
|
||||
Self {
|
||||
epoch_length,
|
||||
period,
|
||||
client: Default::default(),
|
||||
block_state_by_hash: RwLock::new(LruCache::new(STATE_CACHE_NUM)),
|
||||
proposals: Default::default(),
|
||||
signer: Default::default(),
|
||||
machine: Spec::new_test_machine(),
|
||||
step_service: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn sign_header(&self, header: &Header) -> Result<(Signature, H256), Error> {
|
||||
|
||||
match self.signer.read().as_ref() {
|
||||
None => {
|
||||
Err(EngineError::RequiresSigner)?
|
||||
}
|
||||
Some(signer) => {
|
||||
let digest = header.hash();
|
||||
match signer.sign(digest) {
|
||||
Ok(sig) => Ok((sig, digest)),
|
||||
Err(e) => Err(EngineError::Custom(e.into()))?,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct an new state from given checkpoint header.
|
||||
fn new_checkpoint_state(&self, header: &Header) -> Result<CliqueBlockState, Error> {
|
||||
debug_assert_eq!(header.number() % self.epoch_length, 0);
|
||||
|
||||
let mut state = CliqueBlockState::new(
|
||||
extract_signers(header)?);
|
||||
|
||||
// TODO(niklasad1): refactor to perform this check in the `CliqueBlockState` constructor instead
|
||||
state.calc_next_timestamp(header.timestamp(), self.period)?;
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
fn state_no_backfill(&self, hash: &H256) -> Option<CliqueBlockState> {
|
||||
self.block_state_by_hash.write().get_mut(hash).cloned()
|
||||
}
|
||||
|
||||
/// Get `CliqueBlockState` for given header, backfill from last checkpoint if needed.
|
||||
fn state(&self, header: &Header) -> Result<CliqueBlockState, Error> {
|
||||
let mut block_state_by_hash = self.block_state_by_hash.write();
|
||||
if let Some(state) = block_state_by_hash.get_mut(&header.hash()) {
|
||||
return Ok(state.clone());
|
||||
}
|
||||
// If we are looking for an checkpoint block state, we can directly reconstruct it.
|
||||
if header.number() % self.epoch_length == 0 {
|
||||
let state = self.new_checkpoint_state(header)?;
|
||||
block_state_by_hash.insert(header.hash(), state.clone());
|
||||
return Ok(state);
|
||||
}
|
||||
// BlockState is not found in memory, which means we need to reconstruct state from last checkpoint.
|
||||
match self.client.read().as_ref().and_then(|w| w.upgrade()) {
|
||||
None => {
|
||||
return Err(EngineError::RequiresClient)?;
|
||||
}
|
||||
Some(c) => {
|
||||
let last_checkpoint_number = header.number() - header.number() % self.epoch_length as u64;
|
||||
debug_assert_ne!(last_checkpoint_number, header.number());
|
||||
|
||||
// Catching up state, note that we don't really store block state for intermediary blocks,
|
||||
// for speed.
|
||||
let backfill_start = time::Instant::now();
|
||||
trace!(target: "engine",
|
||||
"Back-filling block state. last_checkpoint_number: {}, target: {}({}).",
|
||||
last_checkpoint_number, header.number(), header.hash());
|
||||
|
||||
let mut chain: &mut VecDeque<Header> = &mut VecDeque::with_capacity(
|
||||
(header.number() - last_checkpoint_number + 1) as usize);
|
||||
|
||||
// Put ourselves in.
|
||||
chain.push_front(header.clone());
|
||||
|
||||
// populate chain to last checkpoint
|
||||
loop {
|
||||
let (last_parent_hash, last_num) = {
|
||||
let l = chain.front().expect("chain has at least one element; qed");
|
||||
(*l.parent_hash(), l.number())
|
||||
};
|
||||
|
||||
if last_num == last_checkpoint_number + 1 {
|
||||
break;
|
||||
}
|
||||
match c.block_header(BlockId::Hash(last_parent_hash)) {
|
||||
None => {
|
||||
return Err(BlockError::UnknownParent(last_parent_hash))?;
|
||||
}
|
||||
Some(next) => {
|
||||
chain.push_front(next.decode()?);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the state for last checkpoint.
|
||||
let last_checkpoint_hash = *chain.front()
|
||||
.expect("chain has at least one element; qed")
|
||||
.parent_hash();
|
||||
|
||||
let last_checkpoint_header = match c.block_header(BlockId::Hash(last_checkpoint_hash)) {
|
||||
None => return Err(EngineError::CliqueMissingCheckpoint(last_checkpoint_hash))?,
|
||||
Some(header) => header.decode()?,
|
||||
};
|
||||
|
||||
let last_checkpoint_state = match block_state_by_hash.get_mut(&last_checkpoint_hash) {
|
||||
Some(state) => state.clone(),
|
||||
None => self.new_checkpoint_state(&last_checkpoint_header)?,
|
||||
};
|
||||
|
||||
block_state_by_hash.insert(last_checkpoint_header.hash(), last_checkpoint_state.clone());
|
||||
|
||||
// Backfill!
|
||||
let mut new_state = last_checkpoint_state.clone();
|
||||
for item in chain {
|
||||
new_state.apply(item, false)?;
|
||||
}
|
||||
new_state.calc_next_timestamp(header.timestamp(), self.period)?;
|
||||
block_state_by_hash.insert(header.hash(), new_state.clone());
|
||||
|
||||
let elapsed = backfill_start.elapsed();
|
||||
trace!(target: "engine", "Back-filling succeed, took {} ms.", elapsed.as_millis());
|
||||
Ok(new_state)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Engine<EthereumMachine> for Clique {
|
||||
fn name(&self) -> &str { "Clique" }
|
||||
|
||||
fn machine(&self) -> &EthereumMachine { &self.machine }
|
||||
|
||||
// Clique use same fields, nonce + mixHash
|
||||
fn seal_fields(&self, _header: &Header) -> usize { 2 }
|
||||
|
||||
fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 0 }
|
||||
|
||||
fn on_new_block(
|
||||
&self,
|
||||
_block: &mut ExecutedBlock,
|
||||
_epoch_begin: bool,
|
||||
_ancestry: &mut Iterator<Item=ExtendedHeader>,
|
||||
) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Clique has no block reward.
|
||||
fn on_close_block(&self, _block: &mut ExecutedBlock) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_seal_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> {
|
||||
trace!(target: "engine", "on_seal_block");
|
||||
|
||||
let header = &mut block.header;
|
||||
|
||||
let state = self.state_no_backfill(header.parent_hash())
|
||||
.ok_or_else(|| BlockError::UnknownParent(*header.parent_hash()))?;
|
||||
|
||||
let is_checkpoint = header.number() % self.epoch_length == 0;
|
||||
|
||||
header.set_author(NULL_AUTHOR);
|
||||
|
||||
// Cast a random Vote if not checkpoint
|
||||
if !is_checkpoint {
|
||||
// TODO(niklasad1): this will always be false because `proposals` is never written to
|
||||
let votes = self.proposals.read().iter()
|
||||
.filter(|(address, vote_type)| state.is_valid_vote(*address, **vote_type))
|
||||
.map(|(address, vote_type)| (*address, *vote_type))
|
||||
.collect_vec();
|
||||
|
||||
if !votes.is_empty() {
|
||||
// Pick a random vote.
|
||||
let random_vote = rand::thread_rng().gen_range(0 as usize, votes.len());
|
||||
let (beneficiary, vote_type) = votes[random_vote];
|
||||
|
||||
trace!(target: "engine", "Casting vote: beneficiary {}, type {:?} ", beneficiary, vote_type);
|
||||
|
||||
header.set_author(beneficiary);
|
||||
header.set_seal(vote_type.as_rlp());
|
||||
}
|
||||
}
|
||||
|
||||
// Work on clique seal.
|
||||
|
||||
let mut seal: Vec<u8> = Vec::with_capacity(VANITY_LENGTH + SIGNATURE_LENGTH);
|
||||
|
||||
// At this point, extra_data should only contain miner vanity.
|
||||
if header.extra_data().len() != VANITY_LENGTH {
|
||||
Err(BlockError::ExtraDataOutOfBounds(OutOfBounds {
|
||||
min: Some(VANITY_LENGTH),
|
||||
max: Some(VANITY_LENGTH),
|
||||
found: header.extra_data().len()
|
||||
}))?;
|
||||
}
|
||||
// vanity
|
||||
{
|
||||
seal.extend_from_slice(&header.extra_data()[0..VANITY_LENGTH]);
|
||||
}
|
||||
|
||||
// If we are building an checkpoint block, add all signers now.
|
||||
if is_checkpoint {
|
||||
seal.reserve(state.signers().len() * 20);
|
||||
state.signers().iter().foreach(|addr| {
|
||||
seal.extend_from_slice(&addr[..]);
|
||||
});
|
||||
}
|
||||
|
||||
header.set_extra_data(seal.clone());
|
||||
|
||||
// append signature onto extra_data
|
||||
let (sig, _msg) = self.sign_header(&header)?;
|
||||
seal.extend_from_slice(&sig[..]);
|
||||
header.set_extra_data(seal.clone());
|
||||
|
||||
header.compute_hash();
|
||||
|
||||
// locally sealed block don't go through valid_block_family(), so we have to record state here.
|
||||
let mut new_state = state.clone();
|
||||
new_state.apply(&header, is_checkpoint)?;
|
||||
new_state.calc_next_timestamp(header.timestamp(), self.period)?;
|
||||
self.block_state_by_hash.write().insert(header.hash(), new_state);
|
||||
|
||||
trace!(target: "engine", "on_seal_block: finished, final header: {:?}", header);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Clique doesn't require external work to seal, so we always return true here.
|
||||
fn seals_internally(&self) -> Option<bool> {
|
||||
Some(true)
|
||||
}
|
||||
|
||||
/// Returns if we are ready to seal, the real sealing (signing extra_data) is actually done in `on_seal_block()`.
|
||||
fn generate_seal(&self, block: &ExecutedBlock, parent: &Header) -> Seal {
|
||||
trace!(target: "engine", "tried to generate_seal");
|
||||
let null_seal = util::null_seal();
|
||||
|
||||
if block.header.number() == 0 {
|
||||
trace!(target: "engine", "attempted to seal genesis block");
|
||||
return Seal::None;
|
||||
}
|
||||
|
||||
// if sealing period is 0, and not an checkpoint block, refuse to seal
|
||||
if self.period == 0 {
|
||||
if block.transactions.is_empty() && block.header.number() % self.epoch_length != 0 {
|
||||
return Seal::None;
|
||||
}
|
||||
return Seal::Regular(null_seal);
|
||||
}
|
||||
|
||||
// Check we actually have authority to seal.
|
||||
if let Some(author) = self.signer.read().as_ref().map(|x| x.address()) {
|
||||
|
||||
// ensure the voting state exists
|
||||
match self.state(&parent) {
|
||||
Err(e) => {
|
||||
warn!(target: "engine", "generate_seal: can't get parent state(number: {}, hash: {}): {} ",
|
||||
parent.number(), parent.hash(), e);
|
||||
return Seal::None;
|
||||
}
|
||||
Ok(state) => {
|
||||
// Are we authorized to seal?
|
||||
if !state.is_authorized(&author) {
|
||||
trace!(target: "engine", "generate_seal: Not authorized to sign right now.");
|
||||
// wait for one third of period to try again.
|
||||
thread::sleep(Duration::from_secs(self.period / 3 + 1));
|
||||
return Seal::None;
|
||||
}
|
||||
|
||||
let inturn = state.is_inturn(block.header.number(), &author);
|
||||
|
||||
let now = SystemTime::now();
|
||||
|
||||
let limit = match inturn {
|
||||
true => state.next_timestamp_inturn.unwrap_or(now),
|
||||
false => state.next_timestamp_noturn.unwrap_or(now),
|
||||
};
|
||||
|
||||
// Wait for the right moment.
|
||||
if now < limit {
|
||||
trace!(target: "engine",
|
||||
"generate_seal: sleeping to sign: inturn: {}, now: {:?}, to: {:?}.",
|
||||
inturn, now, limit);
|
||||
match limit.duration_since(SystemTime::now()) {
|
||||
Ok(duration) => {
|
||||
thread::sleep(duration);
|
||||
},
|
||||
Err(e) => {
|
||||
warn!(target:"engine", "generate_seal: unable to sleep, err: {}", e);
|
||||
return Seal::None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trace!(target: "engine", "generate_seal: seal ready for block {}, txs: {}.",
|
||||
block.header.number(), block.transactions.len());
|
||||
return Seal::Regular(null_seal);
|
||||
}
|
||||
}
|
||||
}
|
||||
Seal::None
|
||||
}
|
||||
|
||||
fn verify_local_seal(&self, _header: &Header) -> Result<(), Error> { Ok(()) }
|
||||
|
||||
fn verify_block_basic(&self, header: &Header) -> Result<(), Error> {
|
||||
// Largely same as https://github.com/ethereum/go-ethereum/blob/master/consensus/clique/clique.go#L275
|
||||
|
||||
// Ignore genesis block.
|
||||
if header.number() == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Don't waste time checking blocks from the future
|
||||
{
|
||||
let limit = SystemTime::now().checked_add(Duration::from_secs(self.period))
|
||||
.ok_or(BlockError::TimestampOverflow)?;
|
||||
|
||||
// This should succeed under the contraints that the system clock works
|
||||
let limit_as_dur = limit.duration_since(UNIX_EPOCH).map_err(|e| {
|
||||
Box::new(format!("Converting SystemTime to Duration failed: {}", e))
|
||||
})?;
|
||||
|
||||
let hdr = Duration::from_secs(header.timestamp());
|
||||
if hdr > limit_as_dur {
|
||||
let found = UNIX_EPOCH.checked_add(hdr).ok_or(BlockError::TimestampOverflow)?;
|
||||
|
||||
Err(BlockError::TemporarilyInvalid(OutOfBounds {
|
||||
min: None,
|
||||
max: Some(limit),
|
||||
found,
|
||||
}))?
|
||||
}
|
||||
}
|
||||
|
||||
let is_checkpoint = header.number() % self.epoch_length == 0;
|
||||
|
||||
if is_checkpoint && *header.author() != NULL_AUTHOR {
|
||||
return Err(EngineError::CliqueWrongAuthorCheckpoint(Mismatch {
|
||||
expected: 0.into(),
|
||||
found: *header.author(),
|
||||
}))?;
|
||||
}
|
||||
|
||||
let seal_fields = header.decode_seal::<Vec<_>>()?;
|
||||
if seal_fields.len() != 2 {
|
||||
Err(BlockError::InvalidSealArity(Mismatch {
|
||||
expected: 2,
|
||||
found: seal_fields.len(),
|
||||
}))?
|
||||
}
|
||||
|
||||
let mixhash: H256 = seal_fields[0].into();
|
||||
let nonce: H64 = seal_fields[1].into();
|
||||
|
||||
// Nonce must be 0x00..0 or 0xff..f
|
||||
if nonce != NONCE_DROP_VOTE && nonce != NONCE_AUTH_VOTE {
|
||||
Err(EngineError::CliqueInvalidNonce(nonce))?;
|
||||
}
|
||||
|
||||
if is_checkpoint && nonce != NULL_NONCE {
|
||||
Err(EngineError::CliqueInvalidNonce(nonce))?;
|
||||
}
|
||||
|
||||
// Ensure that the mix digest is zero as Clique don't have fork protection currently
|
||||
if mixhash != NULL_MIXHASH {
|
||||
Err(BlockError::MismatchedH256SealElement(Mismatch {
|
||||
expected: NULL_MIXHASH,
|
||||
found: mixhash,
|
||||
}))?
|
||||
}
|
||||
|
||||
let extra_data_len = header.extra_data().len();
|
||||
|
||||
if extra_data_len < VANITY_LENGTH {
|
||||
Err(EngineError::CliqueMissingVanity)?
|
||||
}
|
||||
|
||||
if extra_data_len < VANITY_LENGTH + SIGNATURE_LENGTH {
|
||||
Err(EngineError::CliqueMissingSignature)?
|
||||
}
|
||||
|
||||
let signers = extra_data_len - (VANITY_LENGTH + SIGNATURE_LENGTH);
|
||||
|
||||
// Checkpoint blocks must at least contain one signer
|
||||
if is_checkpoint && signers == 0 {
|
||||
Err(EngineError::CliqueCheckpointNoSigner)?
|
||||
}
|
||||
|
||||
// Addresses must be be divisable by 20
|
||||
if is_checkpoint && signers % ADDRESS_LENGTH != 0 {
|
||||
Err(EngineError::CliqueCheckpointInvalidSigners(signers))?
|
||||
}
|
||||
|
||||
// Ensure that the block doesn't contain any uncles which are meaningless in PoA
|
||||
if *header.uncles_hash() != NULL_UNCLES_HASH {
|
||||
Err(BlockError::InvalidUnclesHash(Mismatch {
|
||||
expected: NULL_UNCLES_HASH,
|
||||
found: *header.uncles_hash(),
|
||||
}))?
|
||||
}
|
||||
|
||||
// Ensure that the block's difficulty is meaningful (may not be correct at this point)
|
||||
if *header.difficulty() != DIFF_INTURN && *header.difficulty() != DIFF_NOTURN {
|
||||
Err(BlockError::DifficultyOutOfBounds(OutOfBounds {
|
||||
min: Some(DIFF_NOTURN),
|
||||
max: Some(DIFF_INTURN),
|
||||
found: *header.difficulty(),
|
||||
}))?
|
||||
}
|
||||
|
||||
// All basic checks passed, continue to next phase
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn verify_block_unordered(&self, _header: &Header) -> Result<(), Error> {
|
||||
// Nothing to check here.
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Verify block family by looking up parent state (backfill if needed), then try to apply current header.
|
||||
/// see https://github.com/ethereum/go-ethereum/blob/master/consensus/clique/clique.go#L338
|
||||
fn verify_block_family(&self, header: &Header, parent: &Header) -> Result<(), Error> {
|
||||
// Ignore genesis block.
|
||||
if header.number() == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// parent sanity check
|
||||
if parent.hash() != *header.parent_hash() || header.number() != parent.number() + 1 {
|
||||
Err(BlockError::UnknownParent(parent.hash()))?
|
||||
}
|
||||
|
||||
// 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))
|
||||
.ok_or(BlockError::TimestampOverflow)?;
|
||||
|
||||
Err(BlockError::InvalidTimestamp(OutOfBounds {
|
||||
min: None,
|
||||
max,
|
||||
found,
|
||||
}))?
|
||||
}
|
||||
|
||||
// Retrieve the parent state
|
||||
let parent_state = self.state(&parent)?;
|
||||
// Try to apply current state, apply() will further check signer and recent signer.
|
||||
let mut new_state = parent_state.clone();
|
||||
new_state.apply(header, header.number() % self.epoch_length == 0)?;
|
||||
new_state.calc_next_timestamp(header.timestamp(), self.period)?;
|
||||
self.block_state_by_hash.write().insert(header.hash(), new_state);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn genesis_epoch_data(&self, header: &Header, _call: &Call) -> Result<Vec<u8>, String> {
|
||||
let mut state = self.new_checkpoint_state(header).expect("Unable to parse genesis data.");
|
||||
state.calc_next_timestamp(header.timestamp(), self.period).map_err(|e| format!("{}", e))?;
|
||||
self.block_state_by_hash.write().insert(header.hash(), state);
|
||||
|
||||
// no proof.
|
||||
Ok(Vec::new())
|
||||
}
|
||||
|
||||
// Our task here is to set difficulty
|
||||
fn populate_from_parent(&self, header: &mut Header, parent: &Header) {
|
||||
// TODO(https://github.com/paritytech/parity-ethereum/issues/10410): this is a horrible hack,
|
||||
// it is due to the fact that enact and miner both use OpenBlock::new() which will both call
|
||||
// this function. more refactoring is definitely needed.
|
||||
if header.extra_data().len() < VANITY_LENGTH + SIGNATURE_LENGTH {
|
||||
trace!(target: "engine", "populate_from_parent in sealing");
|
||||
|
||||
// It's unclear how to prevent creating new blocks unless we are authorized, the best way (and geth does this too)
|
||||
// it's just to ignore setting an correct difficulty here, we will check authorization in next step in generate_seal anyway.
|
||||
if let Some(signer) = self.signer.read().as_ref() {
|
||||
let state = match self.state(&parent) {
|
||||
Err(e) => {
|
||||
trace!(target: "engine", "populate_from_parent: Unable to find parent state: {}, ignored.", e);
|
||||
return;
|
||||
}
|
||||
Ok(state) => state,
|
||||
};
|
||||
|
||||
if state.is_authorized(&signer.address()) {
|
||||
if state.is_inturn(header.number(), &signer.address()) {
|
||||
header.set_difficulty(DIFF_INTURN);
|
||||
} else {
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_signer(&self, signer: Box<EngineSigner>) {
|
||||
trace!(target: "engine", "set_signer: {}", signer.address());
|
||||
*self.signer.write() = Some(signer);
|
||||
}
|
||||
|
||||
fn register_client(&self, client: Weak<EngineClient>) {
|
||||
*self.client.write() = Some(client.clone());
|
||||
}
|
||||
|
||||
fn step(&self) {
|
||||
if self.signer.read().is_some() {
|
||||
if let Some(ref weak) = *self.client.read() {
|
||||
if let Some(c) = weak.upgrade() {
|
||||
c.update_sealing();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn stop(&mut self) {
|
||||
if let Some(mut s) = self.step_service.as_mut() {
|
||||
Arc::get_mut(&mut s).map(|x| x.stop());
|
||||
} else {
|
||||
warn!(target: "engine", "Stopping `CliqueStepService` failed requires mutable access");
|
||||
}
|
||||
}
|
||||
|
||||
/// Clique timestamp is set to parent + period , or current time which ever is higher.
|
||||
fn open_block_header_timestamp(&self, parent_timestamp: u64) -> u64 {
|
||||
let now = time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap_or_default();
|
||||
cmp::max(now.as_secs() as u64, parent_timestamp.saturating_add(self.period))
|
||||
}
|
||||
|
||||
fn is_timestamp_valid(&self, header_timestamp: u64, parent_timestamp: u64) -> bool {
|
||||
header_timestamp >= parent_timestamp.saturating_add(self.period)
|
||||
}
|
||||
|
||||
fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice {
|
||||
super::total_difficulty_fork_choice(new, current)
|
||||
}
|
||||
|
||||
// Clique uses the author field for voting, the real author is hidden in the `extra_data` field.
|
||||
// So when executing tx's (like in `enact()`) we want to use the executive author
|
||||
fn executive_author(&self, header: &Header) -> Result<Address, Error> {
|
||||
recover_creator(header)
|
||||
}
|
||||
}
|
||||
41
ethcore/src/engines/clique/params.rs
Normal file
41
ethcore/src/engines/clique/params.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
// 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/>.
|
||||
|
||||
//! Clique specific parameters.
|
||||
|
||||
use ethjson;
|
||||
|
||||
/// `Clique` params.
|
||||
pub struct CliqueParams {
|
||||
/// Period as defined in EIP
|
||||
pub period: u64,
|
||||
/// Epoch length as defined in EIP
|
||||
pub epoch: u64,
|
||||
}
|
||||
|
||||
impl From<ethjson::spec::CliqueParams> for CliqueParams {
|
||||
fn from(p: ethjson::spec::CliqueParams) -> Self {
|
||||
let period = p.period.map_or_else(|| 30000 as u64, Into::into);
|
||||
let epoch = p.epoch.map_or_else(|| 15 as u64, Into::into);
|
||||
|
||||
assert!(epoch > 0);
|
||||
|
||||
CliqueParams {
|
||||
period,
|
||||
epoch,
|
||||
}
|
||||
}
|
||||
}
|
||||
77
ethcore/src/engines/clique/step_service.rs
Normal file
77
ethcore/src/engines/clique/step_service.rs
Normal file
@@ -0,0 +1,77 @@
|
||||
// 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/>.
|
||||
|
||||
|
||||
use std::sync::Weak;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::time::Duration;
|
||||
use std::thread;
|
||||
use std::sync::Arc;
|
||||
|
||||
use engines::Engine;
|
||||
use machine::Machine;
|
||||
|
||||
/// Service that is managing the engine
|
||||
pub struct StepService {
|
||||
shutdown: Arc<AtomicBool>,
|
||||
thread: Option<thread::JoinHandle<()>>,
|
||||
}
|
||||
|
||||
impl StepService {
|
||||
/// Start the `StepService`
|
||||
pub fn start<M: Machine + 'static>(engine: Weak<Engine<M>>) -> Arc<Self> {
|
||||
let shutdown = Arc::new(AtomicBool::new(false));
|
||||
let s = shutdown.clone();
|
||||
|
||||
let thread = thread::Builder::new()
|
||||
.name("CliqueStepService".into())
|
||||
.spawn(move || {
|
||||
// startup delay.
|
||||
thread::sleep(Duration::from_secs(5));
|
||||
|
||||
loop {
|
||||
// see if we are in shutdown.
|
||||
if shutdown.load(Ordering::Acquire) {
|
||||
trace!(target: "miner", "CliqueStepService: received shutdown signal!");
|
||||
break;
|
||||
}
|
||||
|
||||
trace!(target: "miner", "CliqueStepService: triggering sealing");
|
||||
|
||||
// Try sealing
|
||||
engine.upgrade().map(|x| x.step());
|
||||
|
||||
// Yield
|
||||
thread::sleep(Duration::from_millis(2000));
|
||||
}
|
||||
trace!(target: "miner", "CliqueStepService: shutdown.");
|
||||
}).expect("CliqueStepService thread failed");
|
||||
|
||||
Arc::new(StepService {
|
||||
shutdown: s,
|
||||
thread: Some(thread),
|
||||
})
|
||||
}
|
||||
|
||||
/// Stop the `StepService`
|
||||
pub fn stop(&mut self) {
|
||||
trace!(target: "miner", "CliqueStepService: shutting down.");
|
||||
self.shutdown.store(true, Ordering::Release);
|
||||
if let Some(t) = self.thread.take() {
|
||||
t.join().expect("CliqueStepService thread panicked!");
|
||||
}
|
||||
}
|
||||
}
|
||||
804
ethcore/src/engines/clique/tests.rs
Normal file
804
ethcore/src/engines/clique/tests.rs
Normal file
@@ -0,0 +1,804 @@
|
||||
// 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/>.
|
||||
|
||||
//! Consensus tests for `PoA Clique Engine`, see http://eips.ethereum.org/EIPS/eip-225 for more information
|
||||
|
||||
use block::*;
|
||||
use engines::Engine;
|
||||
use error::{Error, ErrorKind};
|
||||
use ethereum_types::{Address, H256};
|
||||
use ethkey::{Secret, KeyPair};
|
||||
use state_db::StateDB;
|
||||
use super::*;
|
||||
use test_helpers::get_temp_state_db;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Possible signers
|
||||
pub const SIGNER_TAGS: [char; 6] = ['A', 'B', 'C', 'D', 'E', 'F'];
|
||||
|
||||
/// Clique block types
|
||||
pub enum CliqueBlockType {
|
||||
/// Epoch transition block must contain list of signers
|
||||
Checkpoint,
|
||||
/// Block with no votes
|
||||
Empty,
|
||||
/// Vote
|
||||
Vote(VoteType),
|
||||
}
|
||||
|
||||
/// Clique tester
|
||||
pub struct CliqueTester {
|
||||
/// Mocked Clique
|
||||
pub clique: Clique,
|
||||
/// Mocked genesis state
|
||||
pub genesis: Header,
|
||||
/// StateDB
|
||||
pub db: StateDB,
|
||||
/// List of signers
|
||||
pub signers: HashMap<char, KeyPair>,
|
||||
}
|
||||
|
||||
impl CliqueTester {
|
||||
/// Create a `Clique` tester with settings
|
||||
pub fn with(epoch: u64, period: u64, initial_signers: Vec<char>) -> Self {
|
||||
assert_eq!(initial_signers.iter().all(|s| SIGNER_TAGS.contains(s)), true,
|
||||
"Not all the initial signers is in SIGNER_TAGS, possible keys are 'A' ..= 'F'");
|
||||
|
||||
let clique = Clique::with_test(epoch, period);
|
||||
let mut genesis = Header::default();
|
||||
let mut signers = HashMap::new();
|
||||
|
||||
let call = |_a, _b| {
|
||||
unimplemented!("Clique doesn't use Engine::Call");
|
||||
};
|
||||
|
||||
let mut extra_data = vec![0; VANITY_LENGTH];
|
||||
|
||||
for &signer in SIGNER_TAGS.iter() {
|
||||
let secret = Secret::from(H256::from(signer as u64));
|
||||
let keypair = KeyPair::from_secret(secret).unwrap();
|
||||
if initial_signers.contains(&signer) {
|
||||
extra_data.extend(&*keypair.address());
|
||||
}
|
||||
signers.insert(signer, keypair);
|
||||
}
|
||||
|
||||
// append dummy signature
|
||||
extra_data.extend(std::iter::repeat(0).take(SIGNATURE_LENGTH));
|
||||
|
||||
genesis.set_extra_data(extra_data);
|
||||
genesis.set_gas_limit(U256::from(0xa00000));
|
||||
genesis.set_difficulty(U256::from(1));
|
||||
genesis.set_seal(util::null_seal());
|
||||
|
||||
clique.genesis_epoch_data(&genesis, &call).expect("Create genesis failed");
|
||||
Self {clique, genesis, db: get_temp_state_db(), signers}
|
||||
}
|
||||
|
||||
/// Get difficulty for a given block
|
||||
pub fn get_difficulty(&self, block_num: BlockNumber, header: &Header, signer: &Address) -> U256 {
|
||||
let state = self.clique.state(header).unwrap();
|
||||
if state.is_inturn(block_num, signer) {
|
||||
DIFF_INTURN
|
||||
} else {
|
||||
DIFF_NOTURN
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the state of a given block
|
||||
// Note, this will read the cache and `will` not work with more than 128 blocks
|
||||
pub fn get_state_at_block(&self, hash: &H256) -> CliqueBlockState {
|
||||
self.clique.block_state_by_hash.write()
|
||||
.get_mut(hash)
|
||||
.expect("CliqueBlockState not found tested failed")
|
||||
.clone()
|
||||
}
|
||||
|
||||
/// Get signers after a certain state
|
||||
// This is generally used to fetch the state after a test has been executed and checked against
|
||||
// the intial list of signers provided in the test
|
||||
pub fn clique_signers(&self, hash: &H256) -> impl Iterator<Item = Address> {
|
||||
self.get_state_at_block(hash).signers().clone().into_iter()
|
||||
}
|
||||
|
||||
/// Fetches all addresses at current `block` and converts them back to `tags (char)` and sorts them
|
||||
/// Addresses are supposed sorted based on address but these tests are using `tags` just for simplicity
|
||||
/// and the order is not important!
|
||||
pub fn into_tags<T: Iterator<Item = Address>>(&self, addr: T) -> Vec<char> {
|
||||
let mut tags: Vec<char> = addr.filter_map(|addr| {
|
||||
for (t, kp) in self.signers.iter() {
|
||||
if addr == kp.address() {
|
||||
return Some(*t)
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
.collect();
|
||||
|
||||
tags.sort();
|
||||
tags
|
||||
}
|
||||
|
||||
/// Create a new `Clique` block and import
|
||||
pub fn new_block_and_import(
|
||||
&self,
|
||||
block_type: CliqueBlockType,
|
||||
last_header: &Header,
|
||||
beneficary: Option<Address>,
|
||||
signer: char,
|
||||
) -> Result<Header, Error> {
|
||||
|
||||
let mut extra_data = vec![0; VANITY_LENGTH];
|
||||
let mut seal = util::null_seal();
|
||||
let last_hash = last_header.hash();
|
||||
|
||||
match block_type {
|
||||
CliqueBlockType::Checkpoint => {
|
||||
let signers = self.clique.state(&last_header).unwrap().signers().clone();
|
||||
for signer in signers {
|
||||
extra_data.extend(&*signer);
|
||||
}
|
||||
}
|
||||
CliqueBlockType::Vote(v) => seal = v.as_rlp(),
|
||||
CliqueBlockType::Empty => (),
|
||||
};
|
||||
|
||||
let db = self.db.boxed_clone();
|
||||
|
||||
let mut block = OpenBlock::new(
|
||||
&self.clique,
|
||||
Default::default(),
|
||||
false,
|
||||
db,
|
||||
&last_header.clone(),
|
||||
Arc::new(vec![last_hash]),
|
||||
beneficary.unwrap_or_default(),
|
||||
(3141562.into(), 31415620.into()),
|
||||
extra_data,
|
||||
false,
|
||||
None,
|
||||
).unwrap();
|
||||
|
||||
{
|
||||
let difficulty = self.get_difficulty(block.header.number(), last_header, &self.signers[&signer].address());
|
||||
let b = block.block_mut();
|
||||
b.header.set_timestamp(last_header.timestamp() + self.clique.period);
|
||||
b.header.set_difficulty(difficulty);
|
||||
b.header.set_seal(seal);
|
||||
|
||||
let sign = ethkey::sign(self.signers[&signer].secret(), &b.header.hash()).unwrap();
|
||||
let mut extra_data = b.header.extra_data().clone();
|
||||
extra_data.extend_from_slice(&*sign);
|
||||
b.header.set_extra_data(extra_data);
|
||||
}
|
||||
|
||||
let current_header = &block.header;
|
||||
self.clique.verify_block_basic(current_header)?;
|
||||
self.clique.verify_block_family(current_header, &last_header)?;
|
||||
|
||||
Ok(current_header.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_signer_with_no_votes() {
|
||||
let tester = CliqueTester::with(10, 1, vec!['A']);
|
||||
|
||||
let empty_block = tester.new_block_and_import(CliqueBlockType::Empty, &tester.genesis, None, 'A').unwrap();
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&empty_block.hash()));
|
||||
assert_eq!(&tags, &['A']);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_signer_two_votes() {
|
||||
let tester = CliqueTester::with(10, 1, vec!['A']);
|
||||
|
||||
// Add a vote for `B` signed by `A`
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &tester.genesis,
|
||||
Some(tester.signers[&'B'].address()), 'A').unwrap();
|
||||
let tags = tester.into_tags(tester.clique_signers(&vote.hash()));
|
||||
assert_eq!(&tags, &['A', 'B']);
|
||||
|
||||
// Add a empty block signed by `B`
|
||||
let empty = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'B').unwrap();
|
||||
|
||||
// Add vote for `C` signed by A but should not be accepted
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &empty,
|
||||
Some(tester.signers[&'C'].address()), 'A').unwrap();
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&vote.hash()));
|
||||
assert_eq!(&tags, &['A', 'B']);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn two_signers_six_votes_deny_last() {
|
||||
let tester = CliqueTester::with(10, 1, vec!['A', 'B']);
|
||||
|
||||
let mut prev_header = tester.genesis.clone();
|
||||
|
||||
// Add two votes for `C` signed by `A` and `B`
|
||||
for &signer in SIGNER_TAGS.iter().take(2) {
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &prev_header,
|
||||
Some(tester.signers[&'C'].address()), signer).unwrap();
|
||||
prev_header = vote.clone();
|
||||
}
|
||||
|
||||
// Add two votes for `D` signed by `A` and `B`
|
||||
for &signer in SIGNER_TAGS.iter().take(2) {
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &prev_header,
|
||||
Some(tester.signers[&'D'].address()), signer).unwrap();
|
||||
prev_header = vote.clone();
|
||||
}
|
||||
|
||||
// Add a empty block signed by `C`
|
||||
let empty = tester.new_block_and_import(CliqueBlockType::Empty, &prev_header, None, 'C').unwrap();
|
||||
prev_header = empty.clone();
|
||||
|
||||
// Add two votes for `E` signed by `A` and `B`
|
||||
for &signer in SIGNER_TAGS.iter().take(2) {
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &prev_header,
|
||||
Some(tester.signers[&'E'].address()), signer).unwrap();
|
||||
prev_header = vote.clone();
|
||||
}
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&prev_header.hash()));
|
||||
assert_eq!(&tags, &['A', 'B', 'C', 'D']);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_signer_dropping_itself() {
|
||||
let tester = CliqueTester::with(10, 1, vec!['A']);
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &tester.genesis,
|
||||
Some(tester.signers[&'A'].address()), 'A').unwrap();
|
||||
let signers = tester.clique_signers(&vote.hash());
|
||||
assert!(signers.count() == 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn two_signers_one_remove_vote_no_consensus() {
|
||||
let tester = CliqueTester::with(10, 1, vec!['A', 'B']);
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &tester.genesis,
|
||||
Some(tester.signers[&'B'].address()), 'A').unwrap();
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&vote.hash()));
|
||||
assert_eq!(&tags, &['A', 'B']);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn two_signers_consensus_remove_b() {
|
||||
let tester = CliqueTester::with(10, 1, vec!['A', 'B']);
|
||||
let first_vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &tester.genesis,
|
||||
Some(tester.signers[&'B'].address()), 'A').unwrap();
|
||||
let second_vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &first_vote,
|
||||
Some(tester.signers[&'B'].address()), 'B').unwrap();
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&second_vote.hash()));
|
||||
assert_eq!(&tags, &['A']);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn three_signers_consensus_remove_c() {
|
||||
let tester = CliqueTester::with(10, 1, vec!['A', 'B', 'C']);
|
||||
let first_vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &tester.genesis,
|
||||
Some(tester.signers[&'C'].address()), 'A').unwrap();
|
||||
let second_vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &first_vote,
|
||||
Some(tester.signers[&'C'].address()), 'B').unwrap();
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&second_vote.hash()));
|
||||
assert_eq!(&tags, &['A', 'B']);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn four_signers_half_no_consensus() {
|
||||
let tester = CliqueTester::with(10, 1, vec!['A', 'B', 'C', 'D']);
|
||||
let first_vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &tester.genesis,
|
||||
Some(tester.signers[&'C'].address()), 'A').unwrap();
|
||||
|
||||
let second_vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &first_vote,
|
||||
Some(tester.signers[&'C'].address()), 'B').unwrap();
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&second_vote.hash()));
|
||||
assert_eq!(&tags, &['A', 'B', 'C', 'D']);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn four_signers_three_consensus_rm() {
|
||||
let tester = CliqueTester::with(10, 1, vec!['A', 'B', 'C', 'D']);
|
||||
|
||||
let mut prev_header = tester.genesis.clone();
|
||||
|
||||
// Three votes to remove `D` signed by ['A', 'B', 'C']
|
||||
for signer in SIGNER_TAGS.iter().take(3) {
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &prev_header,
|
||||
Some(tester.signers[&'D'].address()), *signer).unwrap();
|
||||
prev_header = vote.clone();
|
||||
}
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&prev_header.hash()));
|
||||
assert_eq!(&tags, &['A', 'B', 'C']);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vote_add_only_counted_once_per_signer() {
|
||||
let tester = CliqueTester::with(10, 1, vec!['A', 'B']);
|
||||
|
||||
// Add a vote for `C` signed by `A`
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &tester.genesis,
|
||||
Some(tester.signers[&'C'].address()), 'A').unwrap();
|
||||
// Empty block signed by B`
|
||||
let empty = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'B').unwrap();
|
||||
|
||||
// Add a vote for `C` signed by `A`
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &empty,
|
||||
Some(tester.signers[&'C'].address()), 'A').unwrap();
|
||||
// Empty block signed by `B`
|
||||
let empty = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'B').unwrap();
|
||||
|
||||
// Add a vote for `C` signed by `A`
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &empty,
|
||||
Some(tester.signers[&'C'].address()), 'A').unwrap();
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&vote.hash()));
|
||||
assert_eq!(&tags, &['A', 'B']);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vote_add_concurrently_is_permitted() {
|
||||
let tester = CliqueTester::with(10, 1, vec!['A', 'B']);
|
||||
|
||||
// Add a vote for `C` signed by `A`
|
||||
let b = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &tester.genesis,
|
||||
Some(tester.signers[&'C'].address()), 'A').unwrap();
|
||||
|
||||
// Empty block signed by `B`
|
||||
let b = tester.new_block_and_import(CliqueBlockType::Empty, &b, None, 'B').unwrap();
|
||||
|
||||
// Add a vote for `D` signed by `A`
|
||||
let b = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &b,
|
||||
Some(tester.signers[&'D'].address()), 'A').unwrap();
|
||||
|
||||
// Empty block signed by `B`
|
||||
let b = tester.new_block_and_import(CliqueBlockType::Empty, &b, None, 'B').unwrap();
|
||||
|
||||
// Empty block signed by `A`
|
||||
let b = tester.new_block_and_import(CliqueBlockType::Empty, &b, None, 'A').unwrap();
|
||||
|
||||
// Add a vote for `D` signed by `B`
|
||||
let b = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &b,
|
||||
Some(tester.signers[&'D'].address()), 'B').unwrap();
|
||||
|
||||
// Empty block signed by `A`
|
||||
let b = tester.new_block_and_import(CliqueBlockType::Empty, &b, None, 'A').unwrap();
|
||||
|
||||
// Add a vote for `C` signed by `B`
|
||||
let b = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &b,
|
||||
Some(tester.signers[&'C'].address()), 'B').unwrap();
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&b.hash()));
|
||||
assert_eq!(&tags, &['A', 'B', 'C', 'D']);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vote_rm_only_counted_once_per_signer() {
|
||||
let tester = CliqueTester::with(10, 1, vec!['A', 'B']);
|
||||
|
||||
let mut prev_header = tester.genesis.clone();
|
||||
|
||||
for _ in 0..2 {
|
||||
// Vote to remove `B` signed by `A`
|
||||
let b = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &prev_header,
|
||||
Some(tester.signers[&'B'].address()), 'A').unwrap();
|
||||
// Empty block signed by `B`
|
||||
let b = tester.new_block_and_import(CliqueBlockType::Empty, &b, None, 'B').unwrap();
|
||||
|
||||
prev_header = b.clone();
|
||||
}
|
||||
|
||||
// Add a vote for `B` signed by `A`
|
||||
let b = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &prev_header,
|
||||
Some(tester.signers[&'B'].address()), 'A').unwrap();
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&b.hash()));
|
||||
assert_eq!(&tags, &['A', 'B']);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vote_rm_concurrently_is_permitted() {
|
||||
let tester = CliqueTester::with(100, 1, vec!['A', 'B', 'C', 'D']);
|
||||
|
||||
// Add a vote for `C` signed by `A`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &tester.genesis,
|
||||
Some(tester.signers[&'C'].address()), 'A').unwrap();
|
||||
|
||||
// Empty block signed by `B`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'B').unwrap();
|
||||
// Empty block signed by `C`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'C').unwrap();
|
||||
|
||||
// Add a vote for `D` signed by `A`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block,
|
||||
Some(tester.signers[&'D'].address()), 'A').unwrap();
|
||||
|
||||
// Empty block signed by `B`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'B').unwrap();
|
||||
// Empty block signed by `C`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'C').unwrap();
|
||||
// Empty block signed by `A`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'A').unwrap();
|
||||
|
||||
// Add a vote for `D` signed by `B`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block,
|
||||
Some(tester.signers[&'D'].address()), 'B').unwrap();
|
||||
// Add a vote for `D` signed by `C`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block,
|
||||
Some(tester.signers[&'D'].address()), 'C').unwrap();
|
||||
|
||||
// Empty block signed by `A`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'A').unwrap();
|
||||
// Add a vote for `C` signed by `B`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block,
|
||||
Some(tester.signers[&'C'].address()), 'B').unwrap();
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&block.hash()));
|
||||
assert_eq!(&tags, &['A', 'B']);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vote_to_rm_are_immediate_and_ensure_votes_are_rm() {
|
||||
let tester = CliqueTester::with(100, 1, vec!['A', 'B', 'C']);
|
||||
|
||||
// Vote to remove `B` signed by `C`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &tester.genesis,
|
||||
Some(tester.signers[&'B'].address()), 'C').unwrap();
|
||||
// Vote to remove `C` signed by `A`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block,
|
||||
Some(tester.signers[&'C'].address()), 'A').unwrap();
|
||||
// Vote to remove `C` signed by `B`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block,
|
||||
Some(tester.signers[&'C'].address()), 'B').unwrap();
|
||||
// Vote to remove `B` signed by `A`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block,
|
||||
Some(tester.signers[&'B'].address()), 'A').unwrap();
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&block.hash()));
|
||||
assert_eq!(&tags, &['A', 'B']);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vote_to_rm_are_immediate_and_votes_should_be_dropped_from_kicked_signer() {
|
||||
let tester = CliqueTester::with(100, 1, vec!['A', 'B', 'C']);
|
||||
|
||||
// Vote to add `D` signed by `C`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &tester.genesis,
|
||||
Some(tester.signers[&'D'].address()), 'C').unwrap();
|
||||
// Vote to remove `C` signed by `A`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block,
|
||||
Some(tester.signers[&'C'].address()), 'A').unwrap();
|
||||
|
||||
// Vote to remove `C` signed by `B`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block,
|
||||
Some(tester.signers[&'C'].address()), 'B').unwrap();
|
||||
|
||||
// Vote to add `D` signed by `A`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &block,
|
||||
Some(tester.signers[&'D'].address()), 'A').unwrap();
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&block.hash()));
|
||||
assert_eq!(&tags, &['A', 'B']);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cascading_not_allowed() {
|
||||
let tester = CliqueTester::with(100, 1, vec!['A', 'B', 'C', 'D']);
|
||||
|
||||
// Vote against `C` signed by `A`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &tester.genesis,
|
||||
Some(tester.signers[&'C'].address()), 'A').unwrap();
|
||||
|
||||
// Empty block signed by `B`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'B').unwrap();
|
||||
|
||||
// Empty block signed by `C`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'C').unwrap();
|
||||
|
||||
// Vote against `D` signed by `A`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block,
|
||||
Some(tester.signers[&'D'].address()), 'A').unwrap();
|
||||
|
||||
// Vote against `C` signed by `B`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block,
|
||||
Some(tester.signers[&'C'].address()), 'B').unwrap();
|
||||
|
||||
// Empty block signed by `C`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'C').unwrap();
|
||||
|
||||
// Empty block signed by `A`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'A').unwrap();
|
||||
|
||||
// Vote against `D` signed by `B`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block,
|
||||
Some(tester.signers[&'D'].address()), 'B').unwrap();
|
||||
|
||||
// Vote against `D` signed by `C`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block,
|
||||
Some(tester.signers[&'D'].address()), 'C').unwrap();
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&block.hash()));
|
||||
assert_eq!(&tags, &['A', 'B', 'C']);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn consensus_out_of_bounds_consensus_execute_on_touch() {
|
||||
let tester = CliqueTester::with(100, 1, vec!['A', 'B', 'C', 'D']);
|
||||
|
||||
// Vote against `C` signed by `A`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &tester.genesis,
|
||||
Some(tester.signers[&'C'].address()), 'A').unwrap();
|
||||
|
||||
// Empty block signed by `B`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'B').unwrap();
|
||||
|
||||
// Empty block signed by `C`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'C').unwrap();
|
||||
|
||||
// Vote against `D` signed by `A`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block,
|
||||
Some(tester.signers[&'D'].address()), 'A').unwrap();
|
||||
|
||||
// Vote against `C` signed by `B`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block,
|
||||
Some(tester.signers[&'C'].address()), 'B').unwrap();
|
||||
|
||||
// Empty block signed by `C`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'C').unwrap();
|
||||
|
||||
// Empty block signed by `A`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'A').unwrap();
|
||||
|
||||
// Vote against `D` signed by `B`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block,
|
||||
Some(tester.signers[&'D'].address()), 'B').unwrap();
|
||||
|
||||
// Vote against `D` signed by `C`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block,
|
||||
Some(tester.signers[&'D'].address()), 'C').unwrap();
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&block.hash()));
|
||||
assert_eq!(&tags, &['A', 'B', 'C'], "D should have been removed after 3/4 remove votes");
|
||||
|
||||
// Empty block signed by `A`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'A').unwrap();
|
||||
|
||||
// Vote for `C` signed by `C`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &block,
|
||||
Some(tester.signers[&'C'].address()), 'C').unwrap();
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&block.hash()));
|
||||
assert_eq!(&tags, &['A', 'B']);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn consensus_out_of_bounds_first_touch() {
|
||||
let tester = CliqueTester::with(100, 1, vec!['A', 'B', 'C', 'D']);
|
||||
|
||||
// Vote against `C` signed by `A`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &tester.genesis,
|
||||
Some(tester.signers[&'C'].address()), 'A').unwrap();
|
||||
|
||||
// Empty block signed by `B`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'B').unwrap();
|
||||
|
||||
// Empty block signed by `C`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'C').unwrap();
|
||||
|
||||
// Vote against `D` signed by `A`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block,
|
||||
Some(tester.signers[&'D'].address()), 'A').unwrap();
|
||||
|
||||
// Vote against `C` signed by `B`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block,
|
||||
Some(tester.signers[&'C'].address()), 'B').unwrap();
|
||||
|
||||
// Empty block signed by `C`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'C').unwrap();
|
||||
|
||||
// Empty block signed by `A`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'A').unwrap();
|
||||
|
||||
// Vote against `D` signed by `B`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block,
|
||||
Some(tester.signers[&'D'].address()), 'B').unwrap();
|
||||
|
||||
// Vote against `D` signed by `C`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block,
|
||||
Some(tester.signers[&'D'].address()), 'C').unwrap();
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&block.hash()));
|
||||
assert_eq!(&tags, &['A', 'B', 'C']);
|
||||
|
||||
// Empty block signed by `A`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'A').unwrap();
|
||||
|
||||
// Vote for `C` signed by `B`
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &block,
|
||||
Some(tester.signers[&'C'].address()), 'B').unwrap();
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&block.hash()));
|
||||
assert_eq!(&tags, &['A', 'B', 'C']);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pending_votes_doesnt_survive_authorization_changes() {
|
||||
let tester = CliqueTester::with(100, 1, vec!['A', 'B', 'C', 'D', 'E']);
|
||||
|
||||
let mut prev_header = tester.genesis.clone();
|
||||
|
||||
// Vote for `F` from [`A`, `B`, `C`]
|
||||
for sign in SIGNER_TAGS.iter().take(3) {
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &prev_header,
|
||||
Some(tester.signers[&'F'].address()), *sign).unwrap();
|
||||
prev_header = block.clone();
|
||||
}
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&prev_header.hash()));
|
||||
assert_eq!(&tags, &['A', 'B', 'C', 'D', 'E', 'F'], "F should have been added");
|
||||
|
||||
// Vote against `F` from [`D`, `E`, `B`, `C`]
|
||||
for sign in SIGNER_TAGS.iter().skip(3).chain(SIGNER_TAGS.iter().skip(1).take(2)) {
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &prev_header,
|
||||
Some(tester.signers[&'F'].address()), *sign).unwrap();
|
||||
prev_header = block.clone();
|
||||
}
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&prev_header.hash()));
|
||||
assert_eq!(&tags, &['A', 'B', 'C', 'D', 'E'], "F should have been removed");
|
||||
|
||||
// Vote for `F` from [`D`, `E`]
|
||||
for sign in SIGNER_TAGS.iter().skip(3).take(2) {
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &prev_header,
|
||||
Some(tester.signers[&'F'].address()), *sign).unwrap();
|
||||
prev_header = block.clone();
|
||||
}
|
||||
|
||||
// Vote against `A` from [`B`, `C`, `D`]
|
||||
for sign in SIGNER_TAGS.iter().skip(1).take(3) {
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &prev_header,
|
||||
Some(tester.signers[&'A'].address()), *sign).unwrap();
|
||||
prev_header = block.clone();
|
||||
}
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&prev_header.hash()));
|
||||
assert_eq!(&tags, &['B', 'C', 'D', 'E'], "A should have been removed");
|
||||
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &prev_header,
|
||||
Some(tester.signers[&'F'].address()), 'B').unwrap();
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&block.hash()));
|
||||
assert_eq!(&tags, &['B', 'C', 'D', 'E', 'F'], "F should have been added again");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn epoch_transition_reset_all_votes() {
|
||||
let tester = CliqueTester::with(3, 1, vec!['A', 'B']);
|
||||
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &tester.genesis,
|
||||
Some(tester.signers[&'C'].address()), 'A').unwrap();
|
||||
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'B').unwrap();
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Checkpoint, &block, None, 'A').unwrap();
|
||||
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &block,
|
||||
Some(tester.signers[&'C'].address()), 'B').unwrap();
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&block.hash()));
|
||||
assert_eq!(&tags, &['A', 'B'], "Votes should have been reset after checkpoint");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unauthorized_signer_should_not_be_able_to_sign_block() {
|
||||
let tester = CliqueTester::with(3, 1, vec!['A']);
|
||||
let err = tester.new_block_and_import(CliqueBlockType::Empty, &tester.genesis, None, 'B').unwrap_err();
|
||||
|
||||
match err.kind() {
|
||||
ErrorKind::Engine(EngineError::NotAuthorized(_)) => (),
|
||||
_ => assert!(true == false, "Wrong error kind"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signer_should_not_be_able_to_sign_two_consequtive_blocks() {
|
||||
let tester = CliqueTester::with(3, 1, vec!['A', 'B']);
|
||||
let b = tester.new_block_and_import(CliqueBlockType::Empty, &tester.genesis, None, 'A').unwrap();
|
||||
let err = tester.new_block_and_import(CliqueBlockType::Empty, &b, None, 'A').unwrap_err();
|
||||
|
||||
match err.kind() {
|
||||
ErrorKind::Engine(EngineError::CliqueTooRecentlySigned(_)) => (),
|
||||
_ => assert!(true == false, "Wrong error kind"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn recent_signers_should_not_reset_on_checkpoint() {
|
||||
let tester = CliqueTester::with(3, 1, vec!['A', 'B', 'C']);
|
||||
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &tester.genesis, None, 'A').unwrap();
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'B').unwrap();
|
||||
let block = tester.new_block_and_import(CliqueBlockType::Checkpoint, &block, None, 'A').unwrap();
|
||||
|
||||
let err = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'A').unwrap_err();
|
||||
|
||||
match err.kind() {
|
||||
ErrorKind::Engine(EngineError::CliqueTooRecentlySigned(_)) => (),
|
||||
_ => assert!(true == false, "Wrong error kind"),
|
||||
}
|
||||
}
|
||||
|
||||
// Not part of http://eips.ethereum.org/EIPS/eip-225
|
||||
#[test]
|
||||
fn bonus_consensus_should_keep_track_of_votes_before_latest_per_signer() {
|
||||
let tester = CliqueTester::with(100, 1, vec!['A', 'B', 'C', 'D']);
|
||||
|
||||
// Add a vote for `E` signed by `A`
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &tester.genesis,
|
||||
Some(tester.signers[&'E'].address()), 'A').unwrap();
|
||||
// Empty block signed by `B`
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'B').unwrap();
|
||||
|
||||
// Empty block signed by `C`
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'C').unwrap();
|
||||
|
||||
// Empty block signed by `D`
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'D').unwrap();
|
||||
|
||||
// Add a vote for `F` signed by `A`
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &vote,
|
||||
Some(tester.signers[&'F'].address()), 'A').unwrap();
|
||||
// Empty block signed by `C`
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'C').unwrap();
|
||||
|
||||
// Empty block signed by `D`
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'D').unwrap();
|
||||
|
||||
// Add a vote for `E` signed by `B`
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &vote,
|
||||
Some(tester.signers[&'E'].address()), 'B').unwrap();
|
||||
// Empty block signed by `A`
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'A').unwrap();
|
||||
|
||||
// Empty block signed by `C`
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'C').unwrap();
|
||||
|
||||
// Empty block signed by `D`
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'D').unwrap();
|
||||
|
||||
// Add a vote for `F` signed by `B`
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &vote,
|
||||
Some(tester.signers[&'F'].address()), 'B').unwrap();
|
||||
|
||||
// Empty block signed by A`
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'A').unwrap();
|
||||
|
||||
// Add a vote for `E` signed by `C`
|
||||
let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &vote,
|
||||
Some(tester.signers[&'E'].address()), 'C').unwrap();
|
||||
|
||||
let tags = tester.into_tags(tester.clique_signers(&vote.hash()));
|
||||
assert_eq!(&tags, &['A', 'B', 'C', 'D', 'E']);
|
||||
}
|
||||
115
ethcore/src/engines/clique/util.rs
Normal file
115
ethcore/src/engines/clique/util.rs
Normal file
@@ -0,0 +1,115 @@
|
||||
// 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/>.
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use engines::EngineError;
|
||||
use engines::clique::{ADDRESS_LENGTH, SIGNATURE_LENGTH, VANITY_LENGTH, NULL_NONCE, NULL_MIXHASH};
|
||||
use error::Error;
|
||||
use ethereum_types::{Address, H256};
|
||||
use ethkey::{public_to_address, recover as ec_recover, Signature};
|
||||
use lru_cache::LruCache;
|
||||
use parking_lot::RwLock;
|
||||
use rlp::encode;
|
||||
use types::header::Header;
|
||||
|
||||
/// How many recovered signature to cache in the memory.
|
||||
pub const CREATOR_CACHE_NUM: usize = 4096;
|
||||
lazy_static! {
|
||||
/// key: header hash
|
||||
/// value: creator address
|
||||
static ref CREATOR_BY_HASH: RwLock<LruCache<H256, Address>> = RwLock::new(LruCache::new(CREATOR_CACHE_NUM));
|
||||
}
|
||||
|
||||
/// Recover block creator from signature
|
||||
pub fn recover_creator(header: &Header) -> Result<Address, Error> {
|
||||
// Initialization
|
||||
let mut cache = CREATOR_BY_HASH.write();
|
||||
|
||||
if let Some(creator) = cache.get_mut(&header.hash()) {
|
||||
return Ok(*creator);
|
||||
}
|
||||
|
||||
let data = header.extra_data();
|
||||
if data.len() < VANITY_LENGTH {
|
||||
Err(EngineError::CliqueMissingVanity)?
|
||||
}
|
||||
|
||||
if data.len() < VANITY_LENGTH + SIGNATURE_LENGTH {
|
||||
Err(EngineError::CliqueMissingSignature)?
|
||||
}
|
||||
|
||||
// Split `signed_extra data` and `signature`
|
||||
let (signed_data_slice, signature_slice) = data.split_at(data.len() - SIGNATURE_LENGTH);
|
||||
|
||||
// convert `&[u8]` to `[u8; 65]`
|
||||
let signature = {
|
||||
let mut s = [0; SIGNATURE_LENGTH];
|
||||
s.copy_from_slice(signature_slice);
|
||||
s
|
||||
};
|
||||
|
||||
// modify header and hash it
|
||||
let unsigned_header = &mut header.clone();
|
||||
unsigned_header.set_extra_data(signed_data_slice.to_vec());
|
||||
let msg = unsigned_header.hash();
|
||||
|
||||
let pubkey = ec_recover(&Signature::from(signature), &msg)?;
|
||||
let creator = public_to_address(&pubkey);
|
||||
|
||||
cache.insert(header.hash(), creator.clone());
|
||||
Ok(creator)
|
||||
}
|
||||
|
||||
/// Extract signer list from extra_data.
|
||||
///
|
||||
/// Layout of extra_data:
|
||||
/// ----
|
||||
/// VANITY: 32 bytes
|
||||
/// Signers: N * 32 bytes as hex encoded (20 characters)
|
||||
/// Signature: 65 bytes
|
||||
/// --
|
||||
pub fn extract_signers(header: &Header) -> Result<BTreeSet<Address>, Error> {
|
||||
let data = header.extra_data();
|
||||
|
||||
if data.len() <= VANITY_LENGTH + SIGNATURE_LENGTH {
|
||||
Err(EngineError::CliqueCheckpointNoSigner)?
|
||||
}
|
||||
|
||||
// extract only the portion of extra_data which includes the signer list
|
||||
let signers_raw = &data[(VANITY_LENGTH)..data.len() - (SIGNATURE_LENGTH)];
|
||||
|
||||
if signers_raw.len() % ADDRESS_LENGTH != 0 {
|
||||
Err(EngineError::CliqueCheckpointInvalidSigners(signers_raw.len()))?
|
||||
}
|
||||
|
||||
let num_signers = signers_raw.len() / 20;
|
||||
|
||||
let signers: BTreeSet<Address> = (0..num_signers)
|
||||
.map(|i| {
|
||||
let start = i * ADDRESS_LENGTH;
|
||||
let end = start + ADDRESS_LENGTH;
|
||||
signers_raw[start..end].into()
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(signers)
|
||||
}
|
||||
|
||||
/// Retrieve `null_seal`
|
||||
pub fn null_seal() -> Vec<Vec<u8>> {
|
||||
vec![encode(&NULL_MIXHASH.to_vec()), encode(&NULL_NONCE.to_vec())]
|
||||
}
|
||||
@@ -15,7 +15,9 @@
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use engines::{Engine, Seal};
|
||||
use parity_machine::{Machine, Transactions, TotalScoredHeader};
|
||||
use machine::Machine;
|
||||
use types::header::{Header, ExtendedHeader};
|
||||
use block::ExecutedBlock;
|
||||
|
||||
/// `InstantSeal` params.
|
||||
#[derive(Default, Debug, PartialEq)]
|
||||
@@ -48,11 +50,7 @@ impl<M> InstantSeal<M> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Machine> Engine<M> for InstantSeal<M>
|
||||
where M::LiveBlock: Transactions,
|
||||
M::ExtendedHeader: TotalScoredHeader,
|
||||
<M::ExtendedHeader as TotalScoredHeader>::Value: Ord
|
||||
{
|
||||
impl<M: Machine> Engine<M> for InstantSeal<M> {
|
||||
fn name(&self) -> &str {
|
||||
"InstantSeal"
|
||||
}
|
||||
@@ -61,11 +59,15 @@ impl<M: Machine> Engine<M> for InstantSeal<M>
|
||||
|
||||
fn seals_internally(&self) -> Option<bool> { Some(true) }
|
||||
|
||||
fn generate_seal(&self, block: &M::LiveBlock, _parent: &M::Header) -> Seal {
|
||||
if block.transactions().is_empty() { Seal::None } else { Seal::Regular(Vec::new()) }
|
||||
fn generate_seal(&self, block: &ExecutedBlock, _parent: &Header) -> Seal {
|
||||
if block.transactions.is_empty() {
|
||||
Seal::None
|
||||
} else {
|
||||
Seal::Regular(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_local_seal(&self, _header: &M::Header) -> Result<(), M::Error> {
|
||||
fn verify_local_seal(&self, _header: &Header) -> Result<(), M::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -84,7 +86,7 @@ impl<M: Machine> Engine<M> for InstantSeal<M>
|
||||
header_timestamp >= parent_timestamp
|
||||
}
|
||||
|
||||
fn fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> super::ForkChoice {
|
||||
fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice {
|
||||
super::total_difficulty_fork_choice(new, current)
|
||||
}
|
||||
}
|
||||
@@ -106,9 +108,9 @@ mod tests {
|
||||
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
||||
let genesis_header = spec.genesis_header();
|
||||
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
||||
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::default(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap();
|
||||
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::default(), (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
|
||||
let b = b.close_and_lock().unwrap();
|
||||
if let Seal::Regular(seal) = engine.generate_seal(b.block(), &genesis_header) {
|
||||
if let Seal::Regular(seal) = engine.generate_seal(&b, &genesis_header) {
|
||||
assert!(b.try_seal(engine, seal).is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
mod authority_round;
|
||||
mod basic_authority;
|
||||
mod clique;
|
||||
mod instant_seal;
|
||||
mod null_engine;
|
||||
mod validator_set;
|
||||
@@ -27,14 +28,14 @@ pub mod signer;
|
||||
|
||||
pub use self::authority_round::AuthorityRound;
|
||||
pub use self::basic_authority::BasicAuthority;
|
||||
pub use self::epoch::{EpochVerifier, Transition as EpochTransition};
|
||||
pub use self::instant_seal::{InstantSeal, InstantSealParams};
|
||||
pub use self::null_engine::NullEngine;
|
||||
pub use self::signer::EngineSigner;
|
||||
pub use self::clique::Clique;
|
||||
|
||||
// TODO [ToDr] Remove re-export (#10130)
|
||||
pub use types::engines::ForkChoice;
|
||||
pub use types::engines::epoch;
|
||||
pub use types::engines::epoch::{self, Transition as EpochTransition};
|
||||
|
||||
use std::sync::{Weak, Arc};
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
@@ -44,21 +45,24 @@ use builtin::Builtin;
|
||||
use vm::{EnvInfo, Schedule, CreateContractAddress, CallType, ActionValue};
|
||||
use error::Error;
|
||||
use types::BlockNumber;
|
||||
use types::header::Header;
|
||||
use types::header::{Header, ExtendedHeader};
|
||||
use snapshot::SnapshotComponents;
|
||||
use spec::CommonParams;
|
||||
use types::transaction::{self, UnverifiedTransaction, SignedTransaction};
|
||||
|
||||
use ethkey::{Signature};
|
||||
use parity_machine::{Machine, LocalizedMachine as Localized, TotalScoredHeader};
|
||||
use ethereum_types::{H256, U256, Address};
|
||||
use machine::{self, Machine, AuxiliaryRequest, AuxiliaryData};
|
||||
use ethereum_types::{H64, H256, U256, Address};
|
||||
use unexpected::{Mismatch, OutOfBounds};
|
||||
use bytes::Bytes;
|
||||
use types::ancestry_action::AncestryAction;
|
||||
use block::ExecutedBlock;
|
||||
|
||||
/// Default EIP-210 contract code.
|
||||
/// As defined in https://github.com/ethereum/EIPs/pull/210
|
||||
pub const DEFAULT_BLOCKHASH_CONTRACT: &'static str = "73fffffffffffffffffffffffffffffffffffffffe33141561006a5760014303600035610100820755610100810715156100455760003561010061010083050761010001555b6201000081071515610064576000356101006201000083050761020001555b5061013e565b4360003512151561008457600060405260206040f361013d565b61010060003543031315156100a857610100600035075460605260206060f361013c565b6101006000350715156100c55762010000600035430313156100c8565b60005b156100ea576101006101006000350507610100015460805260206080f361013b565b620100006000350715156101095763010000006000354303131561010c565b60005b1561012f57610100620100006000350507610200015460a052602060a0f361013a565b600060c052602060c0f35b5b5b5b5b";
|
||||
/// The number of generations back that uncles can be.
|
||||
pub const MAX_UNCLE_AGE: usize = 6;
|
||||
|
||||
/// Voting errors.
|
||||
#[derive(Debug)]
|
||||
@@ -83,12 +87,45 @@ pub enum EngineError {
|
||||
RequiresClient,
|
||||
/// Invalid engine specification or implementation.
|
||||
InvalidEngine,
|
||||
/// Requires signer ref, but none registered.
|
||||
RequiresSigner,
|
||||
/// Checkpoint is missing
|
||||
CliqueMissingCheckpoint(H256),
|
||||
/// Missing vanity data
|
||||
CliqueMissingVanity,
|
||||
/// Missing signature
|
||||
CliqueMissingSignature,
|
||||
/// Missing signers
|
||||
CliqueCheckpointNoSigner,
|
||||
/// List of signers is invalid
|
||||
CliqueCheckpointInvalidSigners(usize),
|
||||
/// Wrong author on a checkpoint
|
||||
CliqueWrongAuthorCheckpoint(Mismatch<Address>),
|
||||
/// Wrong checkpoint authors recovered
|
||||
CliqueFaultyRecoveredSigners(Vec<String>),
|
||||
/// Invalid nonce (should contain vote)
|
||||
CliqueInvalidNonce(H64),
|
||||
/// The signer signed a block to recently
|
||||
CliqueTooRecentlySigned(Address),
|
||||
/// Custom
|
||||
Custom(String),
|
||||
}
|
||||
|
||||
impl fmt::Display for EngineError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use self::EngineError::*;
|
||||
let msg = match *self {
|
||||
CliqueMissingCheckpoint(ref hash) => format!("Missing checkpoint block: {}", hash),
|
||||
CliqueMissingVanity => format!("Extra data is missing vanity data"),
|
||||
CliqueMissingSignature => format!("Extra data is missing signature"),
|
||||
CliqueCheckpointInvalidSigners(len) => format!("Checkpoint block list was of length: {} of checkpoint but
|
||||
it needs to be bigger than zero and a divisible by 20", len),
|
||||
CliqueCheckpointNoSigner => format!("Checkpoint block list of signers was empty"),
|
||||
CliqueInvalidNonce(ref mis) => format!("Unexpected nonce {} expected {} or {}", mis, 0_u64, u64::max_value()),
|
||||
CliqueWrongAuthorCheckpoint(ref oob) => format!("Unexpected checkpoint author: {}", oob),
|
||||
CliqueFaultyRecoveredSigners(ref mis) => format!("Faulty recovered signers {:?}", mis),
|
||||
CliqueTooRecentlySigned(ref address) => format!("The signer: {} has signed a block too recently", address),
|
||||
Custom(ref s) => s.clone(),
|
||||
DoubleVote(ref address) => format!("Author {} issued too many blocks.", address),
|
||||
NotProposer(ref mis) => format!("Author is not a current proposer: {}", mis),
|
||||
NotAuthorized(ref address) => format!("Signer {} is not authorized.", address),
|
||||
@@ -98,6 +135,7 @@ impl fmt::Display for EngineError {
|
||||
FailedSystemCall(ref msg) => format!("Failed to make system call: {}", msg),
|
||||
MalformedMessage(ref msg) => format!("Received malformed consensus message: {}", msg),
|
||||
RequiresClient => format!("Call requires client but none registered"),
|
||||
RequiresSigner => format!("Call requires signer but none registered"),
|
||||
InvalidEngine => format!("Invalid engine specification or implementation"),
|
||||
};
|
||||
|
||||
@@ -118,7 +156,7 @@ pub enum Seal {
|
||||
Proposal(Vec<Bytes>),
|
||||
/// Regular block seal; should be part of the blockchain.
|
||||
Regular(Vec<Bytes>),
|
||||
/// Engine does generate seal for this block right now.
|
||||
/// Engine does not generate seal for this block right now.
|
||||
None,
|
||||
}
|
||||
|
||||
@@ -176,8 +214,7 @@ pub type PendingTransitionStore<'a> = Fn(H256) -> Option<epoch::PendingTransitio
|
||||
/// Proof dependent on state.
|
||||
pub trait StateDependentProof<M: Machine>: Send + Sync {
|
||||
/// Generate a proof, given the state.
|
||||
// TODO: make this into an &M::StateContext
|
||||
fn generate_proof<'a>(&self, state: &<M as Localized<'a>>::StateContext) -> Result<Vec<u8>, String>;
|
||||
fn generate_proof<'a>(&self, state: &machine::Call) -> Result<Vec<u8>, String>;
|
||||
/// Check a proof generated elsewhere (potentially by a peer).
|
||||
// `engine` needed to check state proofs, while really this should
|
||||
// just be state machine params.
|
||||
@@ -217,7 +254,7 @@ impl<'a, M: Machine> ConstructedVerifier<'a, M> {
|
||||
/// Results of a query of whether an epoch change occurred at the given block.
|
||||
pub enum EpochChange<M: Machine> {
|
||||
/// Cannot determine until more data is passed.
|
||||
Unsure(M::AuxiliaryRequest),
|
||||
Unsure(AuxiliaryRequest),
|
||||
/// No epoch change.
|
||||
No,
|
||||
/// The epoch will change, with proof.
|
||||
@@ -235,17 +272,14 @@ pub trait Engine<M: Machine>: Sync + Send {
|
||||
fn machine(&self) -> &M;
|
||||
|
||||
/// The number of additional header fields required for this engine.
|
||||
fn seal_fields(&self, _header: &M::Header) -> usize { 0 }
|
||||
fn seal_fields(&self, _header: &Header) -> usize { 0 }
|
||||
|
||||
/// Additional engine-specific information for the user/developer concerning `header`.
|
||||
fn extra_info(&self, _header: &M::Header) -> BTreeMap<String, String> { BTreeMap::new() }
|
||||
fn extra_info(&self, _header: &Header) -> BTreeMap<String, String> { BTreeMap::new() }
|
||||
|
||||
/// Maximum number of uncles a block is allowed to declare.
|
||||
fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 0 }
|
||||
|
||||
/// The number of generations back that uncles can be.
|
||||
fn maximum_uncle_age(&self) -> usize { 6 }
|
||||
|
||||
/// Optional maximum gas limit.
|
||||
fn maximum_gas_limit(&self) -> Option<U256> { None }
|
||||
|
||||
@@ -253,18 +287,21 @@ pub trait Engine<M: Machine>: Sync + Send {
|
||||
/// `epoch_begin` set to true if this block kicks off an epoch.
|
||||
fn on_new_block(
|
||||
&self,
|
||||
_block: &mut M::LiveBlock,
|
||||
_block: &mut ExecutedBlock,
|
||||
_epoch_begin: bool,
|
||||
_ancestry: &mut Iterator<Item=M::ExtendedHeader>,
|
||||
_ancestry: &mut Iterator<Item = ExtendedHeader>,
|
||||
) -> Result<(), M::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Block transformation functions, after the transactions.
|
||||
fn on_close_block(&self, _block: &mut M::LiveBlock) -> Result<(), M::Error> {
|
||||
fn on_close_block(&self, _block: &mut ExecutedBlock) -> Result<(), M::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Allow mutating the header during seal generation. Currently only used by Clique.
|
||||
fn on_seal_block(&self, _block: &mut ExecutedBlock) -> Result<(), Error> { Ok(()) }
|
||||
|
||||
/// None means that it requires external input (e.g. PoW) to seal a block.
|
||||
/// Some(true) means the engine is currently prime for seal generation (i.e. node is the current validator).
|
||||
/// Some(false) means that the node might seal internally but is not qualified now.
|
||||
@@ -279,7 +316,7 @@ pub trait Engine<M: Machine>: Sync + Send {
|
||||
///
|
||||
/// It is fine to require access to state or a full client for this function, since
|
||||
/// light clients do not generate seals.
|
||||
fn generate_seal(&self, _block: &M::LiveBlock, _parent: &M::Header) -> Seal { Seal::None }
|
||||
fn generate_seal(&self, _block: &ExecutedBlock, _parent: &Header) -> Seal { Seal::None }
|
||||
|
||||
/// Verify a locally-generated seal of a header.
|
||||
///
|
||||
@@ -291,25 +328,25 @@ pub trait Engine<M: Machine>: Sync + Send {
|
||||
///
|
||||
/// It is fine to require access to state or a full client for this function, since
|
||||
/// light clients do not generate seals.
|
||||
fn verify_local_seal(&self, header: &M::Header) -> Result<(), M::Error>;
|
||||
fn verify_local_seal(&self, header: &Header) -> Result<(), M::Error>;
|
||||
|
||||
/// Phase 1 quick block verification. Only does checks that are cheap. Returns either a null `Ok` or a general error detailing the problem with import.
|
||||
/// The verification module can optionally avoid checking the seal (`check_seal`), if seal verification is disabled this method won't be called.
|
||||
fn verify_block_basic(&self, _header: &M::Header) -> Result<(), M::Error> { Ok(()) }
|
||||
fn verify_block_basic(&self, _header: &Header) -> Result<(), M::Error> { Ok(()) }
|
||||
|
||||
/// Phase 2 verification. Perform costly checks such as transaction signatures. Returns either a null `Ok` or a general error detailing the problem with import.
|
||||
/// The verification module can optionally avoid checking the seal (`check_seal`), if seal verification is disabled this method won't be called.
|
||||
fn verify_block_unordered(&self, _header: &M::Header) -> Result<(), M::Error> { Ok(()) }
|
||||
fn verify_block_unordered(&self, _header: &Header) -> Result<(), M::Error> { Ok(()) }
|
||||
|
||||
/// Phase 3 verification. Check block information against parent. Returns either a null `Ok` or a general error detailing the problem with import.
|
||||
fn verify_block_family(&self, _header: &M::Header, _parent: &M::Header) -> Result<(), M::Error> { Ok(()) }
|
||||
fn verify_block_family(&self, _header: &Header, _parent: &Header) -> Result<(), M::Error> { Ok(()) }
|
||||
|
||||
/// Phase 4 verification. Verify block header against potentially external data.
|
||||
/// Should only be called when `register_client` has been called previously.
|
||||
fn verify_block_external(&self, _header: &M::Header) -> Result<(), M::Error> { Ok(()) }
|
||||
fn verify_block_external(&self, _header: &Header) -> Result<(), M::Error> { Ok(()) }
|
||||
|
||||
/// Genesis epoch data.
|
||||
fn genesis_epoch_data<'a>(&self, _header: &M::Header, _state: &<M as Localized<'a>>::StateContext) -> Result<Vec<u8>, String> { Ok(Vec::new()) }
|
||||
fn genesis_epoch_data<'a>(&self, _header: &Header, _state: &machine::Call) -> Result<Vec<u8>, String> { Ok(Vec::new()) }
|
||||
|
||||
/// Whether an epoch change is signalled at the given header but will require finality.
|
||||
/// If a change can be enacted immediately then return `No` from this function but
|
||||
@@ -320,7 +357,7 @@ pub trait Engine<M: Machine>: Sync + Send {
|
||||
/// Return `Yes` or `No` when the answer is definitively known.
|
||||
///
|
||||
/// Should not interact with state.
|
||||
fn signals_epoch_end<'a>(&self, _header: &M::Header, _aux: <M as Localized<'a>>::AuxiliaryData)
|
||||
fn signals_epoch_end<'a>(&self, _header: &Header, _aux: AuxiliaryData<'a>)
|
||||
-> EpochChange<M>
|
||||
{
|
||||
EpochChange::No
|
||||
@@ -336,9 +373,9 @@ pub trait Engine<M: Machine>: Sync + Send {
|
||||
/// Return optional transition proof.
|
||||
fn is_epoch_end(
|
||||
&self,
|
||||
_chain_head: &M::Header,
|
||||
_chain_head: &Header,
|
||||
_finalized: &[H256],
|
||||
_chain: &Headers<M::Header>,
|
||||
_chain: &Headers<Header>,
|
||||
_transition_store: &PendingTransitionStore,
|
||||
) -> Option<Vec<u8>> {
|
||||
None
|
||||
@@ -355,8 +392,8 @@ pub trait Engine<M: Machine>: Sync + Send {
|
||||
/// Return optional transition proof.
|
||||
fn is_epoch_end_light(
|
||||
&self,
|
||||
_chain_head: &M::Header,
|
||||
_chain: &Headers<M::Header>,
|
||||
_chain_head: &Header,
|
||||
_chain: &Headers<Header>,
|
||||
_transition_store: &PendingTransitionStore,
|
||||
) -> Option<Vec<u8>> {
|
||||
None
|
||||
@@ -364,22 +401,18 @@ pub trait Engine<M: Machine>: Sync + Send {
|
||||
|
||||
/// Create an epoch verifier from validation proof and a flag indicating
|
||||
/// whether finality is required.
|
||||
fn epoch_verifier<'a>(&self, _header: &M::Header, _proof: &'a [u8]) -> ConstructedVerifier<'a, M> {
|
||||
ConstructedVerifier::Trusted(Box::new(self::epoch::NoOp))
|
||||
fn epoch_verifier<'a>(&self, _header: &Header, _proof: &'a [u8]) -> ConstructedVerifier<'a, M> {
|
||||
ConstructedVerifier::Trusted(Box::new(NoOp))
|
||||
}
|
||||
|
||||
/// Populate a header's fields based on its parent's header.
|
||||
/// Usually implements the chain scoring rule based on weight.
|
||||
fn populate_from_parent(&self, _header: &mut M::Header, _parent: &M::Header) { }
|
||||
fn populate_from_parent(&self, _header: &mut Header, _parent: &Header) { }
|
||||
|
||||
/// Handle any potential consensus messages;
|
||||
/// updating consensus state and potentially issuing a new one.
|
||||
fn handle_message(&self, _message: &[u8]) -> Result<(), EngineError> { Err(EngineError::UnexpectedMessage) }
|
||||
|
||||
/// Find out if the block is a proposal block and should not be inserted into the DB.
|
||||
/// Takes a header of a fully verified block.
|
||||
fn is_proposal(&self, _verified_header: &M::Header) -> bool { false }
|
||||
|
||||
/// Register a component which signs consensus messages.
|
||||
fn set_signer(&self, _signer: Box<EngineSigner>) {}
|
||||
|
||||
@@ -393,7 +426,7 @@ pub trait Engine<M: Machine>: Sync + Send {
|
||||
fn step(&self) {}
|
||||
|
||||
/// Stops any services that the may hold the Engine and makes it safe to drop.
|
||||
fn stop(&self) {}
|
||||
fn stop(&mut self) {}
|
||||
|
||||
/// Create a factory for building snapshot chunks and restoring from them.
|
||||
/// Returning `None` indicates that this engine doesn't support snapshot creation.
|
||||
@@ -421,16 +454,21 @@ pub trait Engine<M: Machine>: Sync + Send {
|
||||
|
||||
/// Gather all ancestry actions. Called at the last stage when a block is committed. The Engine must guarantee that
|
||||
/// the ancestry exists.
|
||||
fn ancestry_actions(&self, _header: &M::Header, _ancestry: &mut Iterator<Item=M::ExtendedHeader>) -> Vec<AncestryAction> {
|
||||
fn ancestry_actions(&self, _header: &Header, _ancestry: &mut Iterator<Item = ExtendedHeader>) -> Vec<AncestryAction> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
/// Check whether the given new block is the best block, after finalization check.
|
||||
fn fork_choice(&self, new: &M::ExtendedHeader, best: &M::ExtendedHeader) -> ForkChoice;
|
||||
fn fork_choice(&self, new: &ExtendedHeader, best: &ExtendedHeader) -> ForkChoice;
|
||||
|
||||
/// Returns author should used when executing tx's for this block.
|
||||
fn executive_author(&self, header: &Header) -> Result<Address, Error> {
|
||||
Ok(*header.author())
|
||||
}
|
||||
}
|
||||
|
||||
/// Check whether a given block is the best block based on the default total difficulty rule.
|
||||
pub fn total_difficulty_fork_choice<T: TotalScoredHeader>(new: &T, best: &T) -> ForkChoice where <T as TotalScoredHeader>::Value: Ord {
|
||||
pub fn total_difficulty_fork_choice(new: &ExtendedHeader, best: &ExtendedHeader) -> ForkChoice {
|
||||
if new.total_score() > best.total_score() {
|
||||
ForkChoice::New
|
||||
} else {
|
||||
@@ -523,3 +561,29 @@ pub trait EthEngine: Engine<::machine::EthereumMachine> {
|
||||
|
||||
// convenience wrappers for existing functions.
|
||||
impl<T> EthEngine for T where T: Engine<::machine::EthereumMachine> { }
|
||||
|
||||
/// Verifier for all blocks within an epoch with self-contained state.
|
||||
pub trait EpochVerifier<M: machine::Machine>: Send + Sync {
|
||||
/// Lightly verify the next block header.
|
||||
/// This may not be a header belonging to a different epoch.
|
||||
fn verify_light(&self, header: &Header) -> Result<(), M::Error>;
|
||||
|
||||
/// Perform potentially heavier checks on the next block header.
|
||||
fn verify_heavy(&self, header: &Header) -> Result<(), M::Error> {
|
||||
self.verify_light(header)
|
||||
}
|
||||
|
||||
/// Check a finality proof against this epoch verifier.
|
||||
/// Returns `Some(hashes)` if the proof proves finality of these hashes.
|
||||
/// Returns `None` if the proof doesn't prove anything.
|
||||
fn check_finality_proof(&self, _proof: &[u8]) -> Option<Vec<H256>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Special "no-op" verifier for stateless, epoch-less engines.
|
||||
pub struct NoOp;
|
||||
|
||||
impl<M: machine::Machine> EpochVerifier<M> for NoOp {
|
||||
fn verify_light(&self, _header: &Header) -> Result<(), M::Error> { Ok(()) }
|
||||
}
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
use engines::Engine;
|
||||
use engines::block_reward::{self, RewardKind};
|
||||
use ethereum_types::U256;
|
||||
use machine::WithRewards;
|
||||
use parity_machine::{Machine, Header, LiveBlock, TotalScoredHeader};
|
||||
use machine::Machine;
|
||||
use types::BlockNumber;
|
||||
use types::header::{Header, ExtendedHeader};
|
||||
use block::ExecutedBlock;
|
||||
|
||||
/// Params for a null engine.
|
||||
#[derive(Clone, Default)]
|
||||
@@ -58,26 +59,23 @@ impl<M: Default> Default for NullEngine<M> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Machine + WithRewards> Engine<M> for NullEngine<M>
|
||||
where M::ExtendedHeader: TotalScoredHeader,
|
||||
<M::ExtendedHeader as TotalScoredHeader>::Value: Ord
|
||||
{
|
||||
impl<M: Machine> Engine<M> for NullEngine<M> {
|
||||
fn name(&self) -> &str {
|
||||
"NullEngine"
|
||||
}
|
||||
|
||||
fn machine(&self) -> &M { &self.machine }
|
||||
|
||||
fn on_close_block(&self, block: &mut M::LiveBlock) -> Result<(), M::Error> {
|
||||
fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), M::Error> {
|
||||
use std::ops::Shr;
|
||||
|
||||
let author = *LiveBlock::header(&*block).author();
|
||||
let number = LiveBlock::header(&*block).number();
|
||||
let author = *block.header.author();
|
||||
let number = block.header.number();
|
||||
|
||||
let reward = self.params.block_reward;
|
||||
if reward == U256::zero() { return Ok(()) }
|
||||
|
||||
let n_uncles = LiveBlock::uncles(&*block).len();
|
||||
let n_uncles = block.uncles.len();
|
||||
|
||||
let mut rewards = Vec::new();
|
||||
|
||||
@@ -86,7 +84,7 @@ impl<M: Machine + WithRewards> Engine<M> for NullEngine<M>
|
||||
rewards.push((author, RewardKind::Author, result_block_reward));
|
||||
|
||||
// bestow uncle rewards.
|
||||
for u in LiveBlock::uncles(&*block) {
|
||||
for u in &block.uncles {
|
||||
let uncle_author = u.author();
|
||||
let result_uncle_reward = (reward * U256::from(8 + u.number() - number)).shr(3);
|
||||
rewards.push((*uncle_author, RewardKind::uncle(number, u.number()), result_uncle_reward));
|
||||
@@ -97,7 +95,7 @@ impl<M: Machine + WithRewards> Engine<M> for NullEngine<M>
|
||||
|
||||
fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 2 }
|
||||
|
||||
fn verify_local_seal(&self, _header: &M::Header) -> Result<(), M::Error> {
|
||||
fn verify_local_seal(&self, _header: &Header) -> Result<(), M::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -105,7 +103,7 @@ impl<M: Machine + WithRewards> Engine<M> for NullEngine<M>
|
||||
Some(Box::new(::snapshot::PowSnapshot::new(10000, 10000)))
|
||||
}
|
||||
|
||||
fn fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> super::ForkChoice {
|
||||
fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice {
|
||||
super::total_difficulty_fork_choice(new, current)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ impl Multi {
|
||||
impl ValidatorSet for Multi {
|
||||
fn default_caller(&self, block_id: BlockId) -> Box<Call> {
|
||||
self.correct_set(block_id).map(|set| set.default_caller(block_id))
|
||||
.unwrap_or(Box::new(|_, _| Err("No validator set for given ID.".into())))
|
||||
.unwrap_or_else(|| Box::new(|_, _| Err("No validator set for given ID.".into())))
|
||||
}
|
||||
|
||||
fn on_epoch_begin(&self, _first: bool, header: &Header, call: &mut SystemCall) -> Result<(), ::error::Error> {
|
||||
@@ -141,7 +141,7 @@ impl ValidatorSet for Multi {
|
||||
*self.block_number.write() = Box::new(move |id| client
|
||||
.upgrade()
|
||||
.ok_or_else(|| "No client!".into())
|
||||
.and_then(|c| c.block_number(id).ok_or("Unknown block".into())));
|
||||
.and_then(|c| c.block_number(id).ok_or_else(|| "Unknown block".into())));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
//! General error types for use in ethcore.
|
||||
|
||||
// Silence: `use of deprecated item 'std::error::Error::cause': replaced by Error::source, which can support downcasting`
|
||||
// https://github.com/paritytech/parity-ethereum/issues/10302
|
||||
#![allow(deprecated)]
|
||||
|
||||
use std::{fmt, error};
|
||||
use std::time::SystemTime;
|
||||
|
||||
@@ -33,7 +37,7 @@ use engines::EngineError;
|
||||
|
||||
pub use executed::{ExecutionError, CallError};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy, Eq)]
|
||||
#[derive(Debug, PartialEq, Clone, Eq)]
|
||||
/// Errors concerning block processing.
|
||||
pub enum BlockError {
|
||||
/// Block has too many uncles.
|
||||
@@ -84,7 +88,7 @@ pub enum BlockError {
|
||||
/// Timestamp header field is too far in future.
|
||||
TemporarilyInvalid(OutOfBounds<SystemTime>),
|
||||
/// Log bloom header field is invalid.
|
||||
InvalidLogBloom(Mismatch<Bloom>),
|
||||
InvalidLogBloom(Box<Mismatch<Bloom>>),
|
||||
/// Number field of header is invalid.
|
||||
InvalidNumber(Mismatch<BlockNumber>),
|
||||
/// Block number isn't sensible.
|
||||
|
||||
@@ -241,17 +241,16 @@ impl Engine<EthereumMachine> for Arc<Ethash> {
|
||||
/// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current).
|
||||
fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> {
|
||||
use std::ops::Shr;
|
||||
use parity_machine::LiveBlock;
|
||||
|
||||
let author = *LiveBlock::header(&*block).author();
|
||||
let number = LiveBlock::header(&*block).number();
|
||||
let author = *block.header.author();
|
||||
let number = block.header.number();
|
||||
|
||||
let rewards = match self.ethash_params.block_reward_contract {
|
||||
Some(ref c) if number >= self.ethash_params.block_reward_contract_transition => {
|
||||
let mut beneficiaries = Vec::new();
|
||||
|
||||
beneficiaries.push((author, RewardKind::Author));
|
||||
for u in LiveBlock::uncles(&*block) {
|
||||
for u in &block.uncles {
|
||||
let uncle_author = u.author();
|
||||
beneficiaries.push((*uncle_author, RewardKind::uncle(number, u.number())));
|
||||
}
|
||||
@@ -274,7 +273,8 @@ impl Engine<EthereumMachine> for Arc<Ethash> {
|
||||
let eras_rounds = self.ethash_params.ecip1017_era_rounds;
|
||||
let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, reward, number);
|
||||
|
||||
let n_uncles = LiveBlock::uncles(&*block).len();
|
||||
//let n_uncles = LiveBlock::uncles(&*block).len();
|
||||
let n_uncles = block.uncles.len();
|
||||
|
||||
// Bestow block rewards.
|
||||
let mut result_block_reward = reward + reward.shr(5) * U256::from(n_uncles);
|
||||
@@ -282,7 +282,7 @@ impl Engine<EthereumMachine> for Arc<Ethash> {
|
||||
rewards.push((author, RewardKind::Author, result_block_reward));
|
||||
|
||||
// Bestow uncle rewards.
|
||||
for u in LiveBlock::uncles(&*block) {
|
||||
for u in &block.uncles {
|
||||
let uncle_author = u.author();
|
||||
let result_uncle_reward = if eras == 0 {
|
||||
(reward * U256::from(8 + u.number() - number)).shr(3)
|
||||
@@ -540,9 +540,9 @@ mod tests {
|
||||
let genesis_header = spec.genesis_header();
|
||||
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
||||
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
||||
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap();
|
||||
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
|
||||
let b = b.close().unwrap();
|
||||
assert_eq!(b.state().balance(&Address::zero()).unwrap(), U256::from_str("4563918244f40000").unwrap());
|
||||
assert_eq!(b.state.balance(&Address::zero()).unwrap(), U256::from_str("4563918244f40000").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -589,15 +589,15 @@ mod tests {
|
||||
let genesis_header = spec.genesis_header();
|
||||
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
||||
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
||||
let mut b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap();
|
||||
let mut b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
|
||||
let mut uncle = Header::new();
|
||||
let uncle_author: Address = "ef2d6d194084c2de36e0dabfce45d046b37d1106".into();
|
||||
uncle.set_author(uncle_author);
|
||||
b.push_uncle(uncle).unwrap();
|
||||
|
||||
let b = b.close().unwrap();
|
||||
assert_eq!(b.state().balance(&Address::zero()).unwrap(), "478eae0e571ba000".into());
|
||||
assert_eq!(b.state().balance(&uncle_author).unwrap(), "3cb71f51fc558000".into());
|
||||
assert_eq!(b.state.balance(&Address::zero()).unwrap(), "478eae0e571ba000".into());
|
||||
assert_eq!(b.state.balance(&uncle_author).unwrap(), "3cb71f51fc558000".into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -607,14 +607,14 @@ mod tests {
|
||||
let genesis_header = spec.genesis_header();
|
||||
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
||||
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
||||
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap();
|
||||
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
|
||||
let b = b.close().unwrap();
|
||||
|
||||
let ubi_contract: Address = "00efdd5883ec628983e9063c7d969fe268bbf310".into();
|
||||
let dev_contract: Address = "00756cf8159095948496617f5fb17ed95059f536".into();
|
||||
assert_eq!(b.state().balance(&Address::zero()).unwrap(), U256::from_str("d8d726b7177a80000").unwrap());
|
||||
assert_eq!(b.state().balance(&ubi_contract).unwrap(), U256::from_str("2b5e3af16b1880000").unwrap());
|
||||
assert_eq!(b.state().balance(&dev_contract).unwrap(), U256::from_str("c249fdd327780000").unwrap());
|
||||
assert_eq!(b.state.balance(&Address::zero()).unwrap(), U256::from_str("d8d726b7177a80000").unwrap());
|
||||
assert_eq!(b.state.balance(&ubi_contract).unwrap(), U256::from_str("2b5e3af16b1880000").unwrap());
|
||||
assert_eq!(b.state.balance(&dev_contract).unwrap(), U256::from_str("c249fdd327780000").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -79,21 +79,16 @@ pub fn new_ellaism<'a, T: Into<SpecParams<'a>>>(params: T) -> Spec {
|
||||
load(params.into(), include_bytes!("../../res/ethereum/ellaism.json"))
|
||||
}
|
||||
|
||||
/// Create a new Easthub mainnet chain spec.
|
||||
pub fn new_easthub<'a, T: Into<SpecParams<'a>>>(params: T) -> Spec {
|
||||
load(params.into(), include_bytes!("../../res/ethereum/easthub.json"))
|
||||
}
|
||||
|
||||
/// Create a new Ethereum Social mainnet chain spec.
|
||||
pub fn new_social<'a, T: Into<SpecParams<'a>>>(params: T) -> Spec {
|
||||
load(params.into(), include_bytes!("../../res/ethereum/social.json"))
|
||||
}
|
||||
|
||||
/// Create a new MIX mainnet chain spec.
|
||||
pub fn new_mix<'a, T: Into<SpecParams<'a>>>(params: T) -> Spec {
|
||||
load(params.into(), include_bytes!("../../res/ethereum/mix.json"))
|
||||
}
|
||||
|
||||
/// Create a new Callisto chain spec
|
||||
pub fn new_callisto<'a, T: Into<SpecParams<'a>>>(params: T) -> Spec {
|
||||
load(params.into(), include_bytes!("../../res/ethereum/callisto.json"))
|
||||
}
|
||||
|
||||
/// Create a new Morden testnet chain spec.
|
||||
pub fn new_morden<'a, T: Into<SpecParams<'a>>>(params: T) -> Spec {
|
||||
load(params.into(), include_bytes!("../../res/ethereum/morden.json"))
|
||||
@@ -109,16 +104,26 @@ pub fn new_kovan<'a, T: Into<SpecParams<'a>>>(params: T) -> Spec {
|
||||
load(params.into(), include_bytes!("../../res/ethereum/kovan.json"))
|
||||
}
|
||||
|
||||
/// Create a new Rinkeby testnet chain spec.
|
||||
pub fn new_rinkeby<'a, T: Into<SpecParams<'a>>>(params: T) -> Spec {
|
||||
load(params.into(), include_bytes!("../../res/ethereum/rinkeby.json"))
|
||||
}
|
||||
|
||||
/// Create a new Görli testnet chain spec.
|
||||
pub fn new_goerli<'a, T: Into<SpecParams<'a>>>(params: T) -> Spec {
|
||||
load(params.into(), include_bytes!("../../res/ethereum/goerli.json"))
|
||||
}
|
||||
|
||||
/// Create a new Kotti testnet chain spec.
|
||||
pub fn new_kotti<'a, T: Into<SpecParams<'a>>>(params: T) -> Spec {
|
||||
load(params.into(), include_bytes!("../../res/ethereum/kotti.json"))
|
||||
}
|
||||
|
||||
/// Create a new POA Sokol testnet chain spec.
|
||||
pub fn new_sokol<'a, T: Into<SpecParams<'a>>>(params: T) -> Spec {
|
||||
load(params.into(), include_bytes!("../../res/ethereum/poasokol.json"))
|
||||
}
|
||||
|
||||
/// Create a new Callisto chaun spec
|
||||
pub fn new_callisto<'a, T: Into<SpecParams<'a>>>(params: T) -> Spec {
|
||||
load(params.into(), include_bytes!("../../res/ethereum/callisto.json"))
|
||||
}
|
||||
|
||||
// For tests
|
||||
|
||||
/// Create a new Foundation Frontier-era chain spec as though it never changes to Homestead.
|
||||
|
||||
@@ -167,7 +167,7 @@ pub enum CallError {
|
||||
/// Couldn't find requested block's state in the chain.
|
||||
StatePruned,
|
||||
/// Couldn't find an amount of gas that didn't result in an exception.
|
||||
Exceptional,
|
||||
Exceptional(vm::Error),
|
||||
/// Corrupt state.
|
||||
StateCorrupt,
|
||||
/// Error executing.
|
||||
@@ -187,7 +187,7 @@ impl fmt::Display for CallError {
|
||||
let msg = match *self {
|
||||
TransactionNotFound => "Transaction couldn't be found in the chain".into(),
|
||||
StatePruned => "Couldn't find the transaction block's state in the chain".into(),
|
||||
Exceptional => "An exception happened in the execution".into(),
|
||||
Exceptional(ref e) => format!("An exception ({}) happened in the execution", e),
|
||||
StateCorrupt => "Stored state found to be corrupted.".into(),
|
||||
Execution(ref e) => format!("{}", e),
|
||||
};
|
||||
@@ -197,4 +197,4 @@ impl fmt::Display for CallError {
|
||||
}
|
||||
|
||||
/// Transaction execution result.
|
||||
pub type ExecutionResult = Result<Executed, ExecutionError>;
|
||||
pub type ExecutionResult = Result<Box<Executed>, ExecutionError>;
|
||||
|
||||
@@ -117,7 +117,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
|
||||
{
|
||||
fn initial_storage_at(&self, key: &H256) -> vm::Result<H256> {
|
||||
if self.state.is_base_storage_root_unchanged(&self.origin_info.address)? {
|
||||
self.state.checkpoint_storage_at(0, &self.origin_info.address, key).map(|v| v.unwrap_or(H256::zero())).map_err(Into::into)
|
||||
self.state.checkpoint_storage_at(0, &self.origin_info.address, key).map(|v| v.unwrap_or_default()).map_err(Into::into)
|
||||
} else {
|
||||
warn!(target: "externalities", "Detected existing account {:#x} where a forced contract creation happened.", self.origin_info.address);
|
||||
Ok(H256::zero())
|
||||
|
||||
@@ -18,7 +18,7 @@ use std::path::Path;
|
||||
use super::test_common::*;
|
||||
use pod_state::PodState;
|
||||
use trace;
|
||||
use client::{EvmTestClient, EvmTestError, TransactResult};
|
||||
use client::{EvmTestClient, EvmTestError, TransactErr, TransactSuccess};
|
||||
use ethjson;
|
||||
use types::transaction::SignedTransaction;
|
||||
use vm::EnvInfo;
|
||||
@@ -90,18 +90,18 @@ pub fn json_chain_test<H: FnMut(&str, HookType)>(json_data: &[u8], start_stop_ho
|
||||
flushln!("{} fail", info);
|
||||
failed.push(name.clone());
|
||||
},
|
||||
Ok(TransactResult::Ok { state_root, .. }) if state_root != post_root => {
|
||||
Ok(Ok(TransactSuccess { state_root, .. })) if state_root != post_root => {
|
||||
println!("{} !!! State mismatch (got: {}, expect: {}", info, state_root, post_root);
|
||||
flushln!("{} fail", info);
|
||||
failed.push(name.clone());
|
||||
},
|
||||
Ok(TransactResult::Err { state_root, ref error, .. }) if state_root != post_root => {
|
||||
Ok(Err(TransactErr { state_root, ref error, .. })) if state_root != post_root => {
|
||||
println!("{} !!! State mismatch (got: {}, expect: {}", info, state_root, post_root);
|
||||
println!("{} !!! Execution error: {:?}", info, error);
|
||||
flushln!("{} fail", info);
|
||||
failed.push(name.clone());
|
||||
},
|
||||
Ok(TransactResult::Err { error, .. }) => {
|
||||
Ok(Err(TransactErr { error, .. })) => {
|
||||
flushln!("{} ok ({:?})", info, error);
|
||||
},
|
||||
Ok(_) => {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
// 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
|
||||
//!
|
||||
@@ -89,7 +90,6 @@ extern crate num;
|
||||
extern crate num_cpus;
|
||||
extern crate parity_bytes as bytes;
|
||||
extern crate parity_crypto;
|
||||
extern crate parity_machine;
|
||||
extern crate parity_snappy as snappy;
|
||||
extern crate parking_lot;
|
||||
extern crate trie_db as trie;
|
||||
@@ -149,6 +149,9 @@ 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,11 +24,11 @@ use ethereum_types::{U256, H256, Address};
|
||||
use rlp::Rlp;
|
||||
use types::transaction::{self, SYSTEM_ADDRESS, UNSIGNED_SENDER, UnverifiedTransaction, SignedTransaction};
|
||||
use types::BlockNumber;
|
||||
use types::header::{Header, ExtendedHeader};
|
||||
use types::header::Header;
|
||||
use vm::{CallType, ActionParams, ActionValue, ParamsType};
|
||||
use vm::{EnvInfo, Schedule, CreateContractAddress};
|
||||
|
||||
use block::{ExecutedBlock, IsBlock};
|
||||
use block::ExecutedBlock;
|
||||
use builtin::Builtin;
|
||||
use call_contract::CallContract;
|
||||
use client::BlockInfo;
|
||||
@@ -36,7 +36,7 @@ use error::Error;
|
||||
use executive::Executive;
|
||||
use spec::CommonParams;
|
||||
use state::{CleanupMode, Substate};
|
||||
use trace::{NoopTracer, NoopVMTracer, Tracer, ExecutiveTracer, RewardType, Tracing};
|
||||
use trace::{NoopTracer, NoopVMTracer};
|
||||
use tx_filter::TransactionFilter;
|
||||
|
||||
/// Parity tries to round block.gas_limit to multiple of this constant
|
||||
@@ -126,7 +126,7 @@ impl EthereumMachine {
|
||||
data: Option<Vec<u8>>,
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
let (code, code_hash) = {
|
||||
let state = block.state();
|
||||
let state = &block.state;
|
||||
|
||||
(state.code(&contract_address)?,
|
||||
state.code_hash(&contract_address)?)
|
||||
@@ -173,7 +173,7 @@ impl EthereumMachine {
|
||||
origin: SYSTEM_ADDRESS,
|
||||
gas,
|
||||
gas_price: 0.into(),
|
||||
value: value.unwrap_or(ActionValue::Transfer(0.into())),
|
||||
value: value.unwrap_or_else(|| ActionValue::Transfer(0.into())),
|
||||
code,
|
||||
code_hash,
|
||||
data,
|
||||
@@ -193,12 +193,12 @@ impl EthereumMachine {
|
||||
/// Push last known block hash to the state.
|
||||
fn push_last_hash(&self, block: &mut ExecutedBlock) -> Result<(), Error> {
|
||||
let params = self.params();
|
||||
if block.header().number() == params.eip210_transition {
|
||||
if block.header.number() == params.eip210_transition {
|
||||
let state = block.state_mut();
|
||||
state.init_code(¶ms.eip210_contract_address, params.eip210_contract_code.clone())?;
|
||||
}
|
||||
if block.header().number() >= params.eip210_transition {
|
||||
let parent_hash = block.header().parent_hash().clone();
|
||||
if block.header.number() >= params.eip210_transition {
|
||||
let parent_hash = *block.header.parent_hash();
|
||||
let _ = self.execute_as_system(
|
||||
block,
|
||||
params.eip210_contract_address,
|
||||
@@ -215,7 +215,7 @@ impl EthereumMachine {
|
||||
self.push_last_hash(block)?;
|
||||
|
||||
if let Some(ref ethash_params) = self.ethash_extensions {
|
||||
if block.header().number() == ethash_params.dao_hardfork_transition {
|
||||
if block.header.number() == ethash_params.dao_hardfork_transition {
|
||||
let state = block.state_mut();
|
||||
for child in ðash_params.dao_hardfork_accounts {
|
||||
let beneficiary = ðash_params.dao_hardfork_beneficiary;
|
||||
@@ -428,19 +428,13 @@ pub enum AuxiliaryRequest {
|
||||
Both,
|
||||
}
|
||||
|
||||
impl ::parity_machine::Machine for EthereumMachine {
|
||||
type Header = Header;
|
||||
type ExtendedHeader = ExtendedHeader;
|
||||
|
||||
type LiveBlock = ExecutedBlock;
|
||||
impl super::Machine for EthereumMachine {
|
||||
type EngineClient = ::client::EngineClient;
|
||||
type AuxiliaryRequest = AuxiliaryRequest;
|
||||
type AncestryAction = ::types::ancestry_action::AncestryAction;
|
||||
|
||||
type Error = Error;
|
||||
|
||||
fn balance(&self, live: &ExecutedBlock, address: &Address) -> Result<U256, Error> {
|
||||
live.state().balance(address).map_err(Into::into)
|
||||
live.state.balance(address).map_err(Into::into)
|
||||
}
|
||||
|
||||
fn add_balance(&self, live: &mut ExecutedBlock, address: &Address, amount: &U256) -> Result<(), Error> {
|
||||
@@ -448,42 +442,6 @@ impl ::parity_machine::Machine for EthereumMachine {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ::parity_machine::LocalizedMachine<'a> for EthereumMachine {
|
||||
type StateContext = Call<'a>;
|
||||
type AuxiliaryData = AuxiliaryData<'a>;
|
||||
}
|
||||
|
||||
/// A state machine that uses block rewards.
|
||||
pub trait WithRewards: ::parity_machine::Machine {
|
||||
/// Note block rewards, traces each reward storing information about benefactor, amount and type
|
||||
/// of reward.
|
||||
fn note_rewards(
|
||||
&self,
|
||||
live: &mut Self::LiveBlock,
|
||||
rewards: &[(Address, RewardType, U256)],
|
||||
) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
impl WithRewards for EthereumMachine {
|
||||
fn note_rewards(
|
||||
&self,
|
||||
live: &mut Self::LiveBlock,
|
||||
rewards: &[(Address, RewardType, U256)],
|
||||
) -> Result<(), Self::Error> {
|
||||
if let Tracing::Enabled(ref mut traces) = *live.traces_mut() {
|
||||
let mut tracer = ExecutiveTracer::default();
|
||||
|
||||
for &(address, ref reward_type, amount) in rewards {
|
||||
tracer.trace_reward(address, amount, reward_type.clone());
|
||||
}
|
||||
|
||||
traces.push(tracer.drain().into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Try to round gas_limit a bit so that:
|
||||
// 1) it will still be in desired range
|
||||
// 2) it will be a nearest (with tendency to increase) multiple of PARITY_GAS_LIMIT_DETERMINANT
|
||||
7
ethcore/src/machine/mod.rs
Normal file
7
ethcore/src/machine/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
//! Generalization of a state machine for a consensus engine.
|
||||
|
||||
mod impls;
|
||||
mod traits;
|
||||
|
||||
pub use self::impls::*;
|
||||
pub use self::traits::*;
|
||||
37
ethcore/src/machine/traits.rs
Normal file
37
ethcore/src/machine/traits.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
// 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/>.
|
||||
|
||||
//! Generalization of a state machine for a consensus engine.
|
||||
//! This will define traits for the header, block, and state of a blockchain.
|
||||
|
||||
use ethereum_types::{U256, Address};
|
||||
use block::ExecutedBlock;
|
||||
|
||||
/// Generalization of types surrounding blockchain-suitable state machines.
|
||||
pub trait Machine: Send + Sync {
|
||||
/// A handle to a blockchain client for this machine.
|
||||
type EngineClient: ?Sized;
|
||||
|
||||
/// Errors which can occur when querying or interacting with the machine.
|
||||
type Error;
|
||||
|
||||
/// Get the balance, in base units, associated with an account.
|
||||
/// Extracts data from the live block.
|
||||
fn balance(&self, live: &ExecutedBlock, address: &Address) -> Result<U256, Self::Error>;
|
||||
|
||||
/// Increment the balance of an account in the state of the live block.
|
||||
fn add_balance(&self, live: &mut ExecutedBlock, address: &Address, amount: &U256) -> Result<(), Self::Error>;
|
||||
}
|
||||
@@ -25,6 +25,7 @@ use call_contract::CallContract;
|
||||
use ethcore_miner::gas_pricer::GasPricer;
|
||||
use ethcore_miner::local_accounts::LocalAccounts;
|
||||
use ethcore_miner::pool::{self, TransactionQueue, VerifiedTransaction, QueueStatus, PrioritizationStrategy};
|
||||
use ethcore_miner::service_transaction_checker::ServiceTransactionChecker;
|
||||
#[cfg(feature = "work-notify")]
|
||||
use ethcore_miner::work_notify::NotifyWork;
|
||||
use ethereum_types::{H256, U256, Address};
|
||||
@@ -46,7 +47,7 @@ use types::header::Header;
|
||||
use types::receipt::RichReceipt;
|
||||
use using_queue::{UsingQueue, GetAction};
|
||||
|
||||
use block::{ClosedBlock, IsBlock, SealedBlock};
|
||||
use block::{ClosedBlock, SealedBlock};
|
||||
use client::{
|
||||
BlockChain, ChainInfo, BlockProducer, SealedBlockImporter, Nonce, TransactionInfo, TransactionId
|
||||
};
|
||||
@@ -214,7 +215,6 @@ impl Author {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct SealingWork {
|
||||
queue: UsingQueue<ClosedBlock>,
|
||||
enabled: bool,
|
||||
@@ -247,6 +247,7 @@ pub struct Miner {
|
||||
engine: Arc<EthEngine>,
|
||||
accounts: Arc<LocalAccounts>,
|
||||
io_channel: RwLock<Option<IoChannel<ClientIoMessage>>>,
|
||||
service_transaction_checker: Option<ServiceTransactionChecker>,
|
||||
}
|
||||
|
||||
impl Miner {
|
||||
@@ -273,6 +274,7 @@ impl Miner {
|
||||
let verifier_options = options.pool_verification_options.clone();
|
||||
let tx_queue_strategy = options.tx_queue_strategy;
|
||||
let nonce_cache_size = cmp::max(4096, limits.max_count / 4);
|
||||
let refuse_service_transactions = options.refuse_service_transactions;
|
||||
|
||||
Miner {
|
||||
sealing: Mutex::new(SealingWork {
|
||||
@@ -293,6 +295,11 @@ impl Miner {
|
||||
accounts: Arc::new(accounts),
|
||||
engine: spec.engine.clone(),
|
||||
io_channel: RwLock::new(None),
|
||||
service_transaction_checker: if refuse_service_transactions {
|
||||
None
|
||||
} else {
|
||||
Some(ServiceTransactionChecker::default())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -351,6 +358,11 @@ impl Miner {
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns ServiceTransactionChecker
|
||||
pub fn service_transaction_checker(&self) -> Option<ServiceTransactionChecker> {
|
||||
self.service_transaction_checker.clone()
|
||||
}
|
||||
|
||||
/// Retrieves an existing pending block iff it's not older than given block number.
|
||||
///
|
||||
/// NOTE: This will not prepare a new pending block if it's not existing.
|
||||
@@ -362,7 +374,7 @@ impl Miner {
|
||||
.and_then(|b| {
|
||||
// to prevent a data race between block import and updating pending block
|
||||
// we allow the number to be equal.
|
||||
if b.block().header().number() >= latest_block_number {
|
||||
if b.header.number() >= latest_block_number {
|
||||
Some(f(b))
|
||||
} else {
|
||||
None
|
||||
@@ -378,7 +390,7 @@ impl Miner {
|
||||
&self.nonce_cache,
|
||||
&*self.engine,
|
||||
&*self.accounts,
|
||||
self.options.refuse_service_transactions,
|
||||
self.service_transaction_checker.as_ref(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -392,7 +404,7 @@ impl Miner {
|
||||
// Open block
|
||||
let (mut open_block, original_work_hash) = {
|
||||
let mut sealing = self.sealing.lock();
|
||||
let last_work_hash = sealing.queue.peek_last_ref().map(|pb| pb.block().header().hash());
|
||||
let last_work_hash = sealing.queue.peek_last_ref().map(|pb| pb.header.hash());
|
||||
let best_hash = chain_info.best_block_hash;
|
||||
|
||||
// check to see if last ClosedBlock in would_seals is actually same parent block.
|
||||
@@ -401,7 +413,7 @@ impl Miner {
|
||||
// if at least one was pushed successfully, close and enqueue new ClosedBlock;
|
||||
// otherwise, leave everything alone.
|
||||
// otherwise, author a fresh block.
|
||||
let mut open_block = match sealing.queue.get_pending_if(|b| b.block().header().parent_hash() == &best_hash) {
|
||||
let mut open_block = match sealing.queue.get_pending_if(|b| b.header.parent_hash() == &best_hash) {
|
||||
Some(old_block) => {
|
||||
trace!(target: "miner", "prepare_block: Already have previous work; updating and returning");
|
||||
// add transactions to old_block
|
||||
@@ -436,7 +448,7 @@ impl Miner {
|
||||
let mut invalid_transactions = HashSet::new();
|
||||
let mut not_allowed_transactions = HashSet::new();
|
||||
let mut senders_to_penalize = HashSet::new();
|
||||
let block_number = open_block.block().header().number();
|
||||
let block_number = open_block.header.number();
|
||||
|
||||
let mut tx_count = 0usize;
|
||||
let mut skipped_transactions = 0usize;
|
||||
@@ -453,7 +465,7 @@ impl Miner {
|
||||
let max_transactions = if min_tx_gas.is_zero() {
|
||||
usize::max_value()
|
||||
} else {
|
||||
MAX_SKIPPED_TRANSACTIONS.saturating_add(cmp::min(*open_block.block().header().gas_limit() / min_tx_gas, u64::max_value().into()).as_u64() as usize)
|
||||
MAX_SKIPPED_TRANSACTIONS.saturating_add(cmp::min(*open_block.header.gas_limit() / min_tx_gas, u64::max_value().into()).as_u64() as usize)
|
||||
};
|
||||
|
||||
let pending: Vec<Arc<_>> = self.transaction_queue.pending(
|
||||
@@ -630,13 +642,16 @@ impl Miner {
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to perform internal sealing (one that does not require work) and handles the result depending on the type of Seal.
|
||||
// TODO: (https://github.com/paritytech/parity-ethereum/issues/10407)
|
||||
// This is only used in authority_round path, and should be refactored to merge with the other seal() path.
|
||||
// Attempts to perform internal sealing (one that does not require work) and handles the result depending on the
|
||||
// type of Seal.
|
||||
fn seal_and_import_block_internally<C>(&self, chain: &C, block: ClosedBlock) -> bool
|
||||
where C: BlockChain + SealedBlockImporter,
|
||||
{
|
||||
{
|
||||
let sealing = self.sealing.lock();
|
||||
if block.transactions().is_empty()
|
||||
if block.transactions.is_empty()
|
||||
&& !self.forced_sealing()
|
||||
&& Instant::now() <= sealing.next_mandatory_reseal
|
||||
{
|
||||
@@ -646,7 +661,7 @@ impl Miner {
|
||||
|
||||
trace!(target: "miner", "seal_block_internally: attempting internal seal.");
|
||||
|
||||
let parent_header = match chain.block_header(BlockId::Hash(*block.header().parent_hash())) {
|
||||
let parent_header = match chain.block_header(BlockId::Hash(*block.header.parent_hash())) {
|
||||
Some(h) => {
|
||||
match h.decode() {
|
||||
Ok(decoded_hdr) => decoded_hdr,
|
||||
@@ -656,7 +671,7 @@ impl Miner {
|
||||
None => return false,
|
||||
};
|
||||
|
||||
match self.engine.generate_seal(block.block(), &parent_header) {
|
||||
match self.engine.generate_seal(&block, &parent_header) {
|
||||
// Save proposal for later seal submission and broadcast it.
|
||||
Seal::Proposal(seal) => {
|
||||
trace!(target: "miner", "Received a Proposal seal.");
|
||||
@@ -705,11 +720,11 @@ impl Miner {
|
||||
/// Prepares work which has to be done to seal.
|
||||
fn prepare_work(&self, block: ClosedBlock, original_work_hash: Option<H256>) {
|
||||
let (work, is_new) = {
|
||||
let block_header = block.block().header().clone();
|
||||
let block_header = block.header.clone();
|
||||
let block_hash = block_header.hash();
|
||||
|
||||
let mut sealing = self.sealing.lock();
|
||||
let last_work_hash = sealing.queue.peek_last_ref().map(|pb| pb.block().header().hash());
|
||||
let last_work_hash = sealing.queue.peek_last_ref().map(|pb| pb.header.hash());
|
||||
|
||||
trace!(
|
||||
target: "miner",
|
||||
@@ -742,7 +757,7 @@ impl Miner {
|
||||
trace!(
|
||||
target: "miner",
|
||||
"prepare_work: leaving (last={:?})",
|
||||
sealing.queue.peek_last_ref().map(|b| b.block().header().hash())
|
||||
sealing.queue.peek_last_ref().map(|b| b.header.hash())
|
||||
);
|
||||
(work, is_new)
|
||||
};
|
||||
@@ -994,7 +1009,7 @@ impl miner::MinerService for Miner {
|
||||
|
||||
let from_pending = || {
|
||||
self.map_existing_pending_block(|sealing| {
|
||||
sealing.transactions()
|
||||
sealing.transactions
|
||||
.iter()
|
||||
.map(|signed| signed.hash())
|
||||
.collect()
|
||||
@@ -1041,7 +1056,7 @@ impl miner::MinerService for Miner {
|
||||
|
||||
let from_pending = || {
|
||||
self.map_existing_pending_block(|sealing| {
|
||||
sealing.transactions()
|
||||
sealing.transactions
|
||||
.iter()
|
||||
.map(|signed| pool::VerifiedTransaction::from_pending_block_transaction(signed.clone()))
|
||||
.map(Arc::new)
|
||||
@@ -1086,9 +1101,9 @@ impl miner::MinerService for Miner {
|
||||
|
||||
fn pending_receipts(&self, best_block: BlockNumber) -> Option<Vec<RichReceipt>> {
|
||||
self.map_existing_pending_block(|pending| {
|
||||
let receipts = pending.receipts();
|
||||
pending.transactions()
|
||||
.into_iter()
|
||||
let receipts = &pending.receipts;
|
||||
pending.transactions
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, tx)| {
|
||||
let prev_gas = if index == 0 { Default::default() } else { receipts[index - 1].gas_used };
|
||||
@@ -1102,7 +1117,7 @@ impl miner::MinerService for Miner {
|
||||
Action::Call(_) => None,
|
||||
Action::Create => {
|
||||
let sender = tx.sender();
|
||||
Some(contract_address(self.engine.create_address_scheme(pending.header().number()), &sender, &tx.nonce, &tx.data).0)
|
||||
Some(contract_address(self.engine.create_address_scheme(pending.header.number()), &sender, &tx.nonce, &tx.data).0)
|
||||
}
|
||||
},
|
||||
logs: receipt.logs.clone(),
|
||||
@@ -1139,10 +1154,10 @@ impl miner::MinerService for Miner {
|
||||
|
||||
// refuse to seal the first block of the chain if it contains hard forks
|
||||
// which should be on by default.
|
||||
if block.block().header().number() == 1 {
|
||||
if block.header.number() == 1 {
|
||||
if let Some(name) = self.engine.params().nonzero_bugfix_hard_fork() {
|
||||
warn!("Your chain specification contains one or more hard forks which are required to be \
|
||||
on by default. Please remove these forks and start your chain again: {}.", name);
|
||||
on by default. Please remove these forks and start your chain again: {}.", name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1180,7 +1195,7 @@ impl miner::MinerService for Miner {
|
||||
self.prepare_pending_block(chain);
|
||||
|
||||
self.sealing.lock().queue.use_last_ref().map(|b| {
|
||||
let header = b.header();
|
||||
let header = &b.header;
|
||||
(header.hash(), header.number(), header.timestamp(), *header.difficulty())
|
||||
})
|
||||
}
|
||||
@@ -1194,9 +1209,9 @@ impl miner::MinerService for Miner {
|
||||
} else {
|
||||
GetAction::Take
|
||||
},
|
||||
|b| &b.hash() == &block_hash
|
||||
|b| &b.header.bare_hash() == &block_hash
|
||||
) {
|
||||
trace!(target: "miner", "Submitted block {}={}={} with seal {:?}", block_hash, b.hash(), b.header().bare_hash(), seal);
|
||||
trace!(target: "miner", "Submitted block {}={} with seal {:?}", block_hash, b.header.bare_hash(), seal);
|
||||
b.lock().try_seal(&*self.engine, seal).or_else(|e| {
|
||||
warn!(target: "miner", "Mined solution rejected: {}", e);
|
||||
Err(ErrorKind::PowInvalid.into())
|
||||
@@ -1207,8 +1222,8 @@ impl miner::MinerService for Miner {
|
||||
};
|
||||
|
||||
result.and_then(|sealed| {
|
||||
let n = sealed.header().number();
|
||||
let h = sealed.header().hash();
|
||||
let n = sealed.header.number();
|
||||
let h = sealed.header.hash();
|
||||
info!(target: "miner", "Submitted block imported OK. #{}: {}", Colour::White.bold().paint(format!("{}", n)), Colour::White.bold().paint(format!("{:x}", h)));
|
||||
Ok(sealed)
|
||||
})
|
||||
@@ -1281,7 +1296,7 @@ impl miner::MinerService for Miner {
|
||||
let nonce_cache = self.nonce_cache.clone();
|
||||
let engine = self.engine.clone();
|
||||
let accounts = self.accounts.clone();
|
||||
let refuse_service_transactions = self.options.refuse_service_transactions;
|
||||
let service_transaction_checker = self.service_transaction_checker.clone();
|
||||
|
||||
let cull = move |chain: &::client::Client| {
|
||||
let client = PoolClient::new(
|
||||
@@ -1289,7 +1304,7 @@ impl miner::MinerService for Miner {
|
||||
&nonce_cache,
|
||||
&*engine,
|
||||
&*accounts,
|
||||
refuse_service_transactions,
|
||||
service_transaction_checker.as_ref(),
|
||||
);
|
||||
queue.cull(client);
|
||||
};
|
||||
@@ -1301,22 +1316,39 @@ impl miner::MinerService for Miner {
|
||||
self.transaction_queue.cull(client);
|
||||
}
|
||||
}
|
||||
if let Some(ref service_transaction_checker) = self.service_transaction_checker {
|
||||
match service_transaction_checker.refresh_cache(chain) {
|
||||
Ok(true) => {
|
||||
trace!(target: "client", "Service transaction cache was refreshed successfully");
|
||||
},
|
||||
Ok(false) => {
|
||||
trace!(target: "client", "Registrar or/and service transactions contract does not exist");
|
||||
},
|
||||
Err(e) => error!(target: "client", "Error occurred while refreshing service transaction cache: {}", e)
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
fn pending_state(&self, latest_block_number: BlockNumber) -> Option<Self::State> {
|
||||
self.map_existing_pending_block(|b| b.state().clone(), latest_block_number)
|
||||
self.map_existing_pending_block(|b| b.state.clone(), latest_block_number)
|
||||
}
|
||||
|
||||
fn pending_block_header(&self, latest_block_number: BlockNumber) -> Option<Header> {
|
||||
self.map_existing_pending_block(|b| b.header().clone(), latest_block_number)
|
||||
self.map_existing_pending_block(|b| b.header.clone(), latest_block_number)
|
||||
}
|
||||
|
||||
fn pending_block(&self, latest_block_number: BlockNumber) -> Option<Block> {
|
||||
self.map_existing_pending_block(|b| b.to_base(), latest_block_number)
|
||||
self.map_existing_pending_block(|b| {
|
||||
Block {
|
||||
header: b.header.clone(),
|
||||
transactions: b.transactions.iter().cloned().map(Into::into).collect(),
|
||||
uncles: b.uncles.to_vec(),
|
||||
}
|
||||
}, latest_block_number)
|
||||
}
|
||||
|
||||
fn pending_transactions(&self, latest_block_number: BlockNumber) -> Option<Vec<SignedTransaction>> {
|
||||
self.map_existing_pending_block(|b| b.transactions().into_iter().cloned().collect(), latest_block_number)
|
||||
self.map_existing_pending_block(|b| b.transactions.iter().cloned().collect(), latest_block_number)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ pub struct PoolClient<'a, C: 'a> {
|
||||
engine: &'a EthEngine,
|
||||
accounts: &'a LocalAccounts,
|
||||
best_block_header: Header,
|
||||
service_transaction_checker: Option<ServiceTransactionChecker>,
|
||||
service_transaction_checker: Option<&'a ServiceTransactionChecker>,
|
||||
}
|
||||
|
||||
impl<'a, C: 'a> Clone for PoolClient<'a, C> {
|
||||
@@ -100,7 +100,7 @@ impl<'a, C: 'a> PoolClient<'a, C> where
|
||||
cache: &'a NonceCache,
|
||||
engine: &'a EthEngine,
|
||||
accounts: &'a LocalAccounts,
|
||||
refuse_service_transactions: bool,
|
||||
service_transaction_checker: Option<&'a ServiceTransactionChecker>,
|
||||
) -> Self {
|
||||
let best_block_header = chain.best_block_header();
|
||||
PoolClient {
|
||||
@@ -109,11 +109,7 @@ impl<'a, C: 'a> PoolClient<'a, C> where
|
||||
engine,
|
||||
accounts,
|
||||
best_block_header,
|
||||
service_transaction_checker: if refuse_service_transactions {
|
||||
None
|
||||
} else {
|
||||
Some(Default::default())
|
||||
},
|
||||
service_transaction_checker,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ impl SnapshotComponents for PoaSnapshot {
|
||||
}
|
||||
|
||||
let header = chain.block_header_data(&transition.block_hash)
|
||||
.ok_or(Error::BlockNotFound(transition.block_hash))?;
|
||||
.ok_or_else(|| Error::BlockNotFound(transition.block_hash))?;
|
||||
|
||||
let entry = {
|
||||
let mut entry_stream = RlpStream::new_list(2);
|
||||
@@ -101,12 +101,12 @@ impl SnapshotComponents for PoaSnapshot {
|
||||
|
||||
let (block, receipts) = chain.block(&block_at)
|
||||
.and_then(|b| chain.block_receipts(&block_at).map(|r| (b, r)))
|
||||
.ok_or(Error::BlockNotFound(block_at))?;
|
||||
.ok_or_else(|| Error::BlockNotFound(block_at))?;
|
||||
let block = block.decode()?;
|
||||
|
||||
let parent_td = chain.block_details(block.header.parent_hash())
|
||||
.map(|d| d.total_difficulty)
|
||||
.ok_or(Error::BlockNotFound(block_at))?;
|
||||
.ok_or_else(|| Error::BlockNotFound(block_at))?;
|
||||
|
||||
rlps.push({
|
||||
let mut stream = RlpStream::new_list(5);
|
||||
|
||||
@@ -116,7 +116,7 @@ impl<'a> PowWorker<'a> {
|
||||
|
||||
let (block, receipts) = self.chain.block(&self.current_hash)
|
||||
.and_then(|b| self.chain.block_receipts(&self.current_hash).map(|r| (b, r)))
|
||||
.ok_or(Error::BlockNotFound(self.current_hash))?;
|
||||
.ok_or_else(|| Error::BlockNotFound(self.current_hash))?;
|
||||
|
||||
let abridged_rlp = AbridgedBlock::from_block_view(&block.view()).into_inner();
|
||||
|
||||
@@ -160,7 +160,7 @@ impl<'a> PowWorker<'a> {
|
||||
|
||||
let (last_header, last_details) = self.chain.block_header_data(&last)
|
||||
.and_then(|n| self.chain.block_details(&last).map(|d| (n, d)))
|
||||
.ok_or(Error::BlockNotFound(last))?;
|
||||
.ok_or_else(|| Error::BlockNotFound(last))?;
|
||||
|
||||
let parent_number = last_header.number() - 1;
|
||||
let parent_hash = last_header.parent_hash();
|
||||
|
||||
@@ -157,7 +157,7 @@ pub fn take_snapshot<W: SnapshotWriter + Send>(
|
||||
processing_threads: usize,
|
||||
) -> Result<(), Error> {
|
||||
let start_header = chain.block_header_data(&block_at)
|
||||
.ok_or(Error::InvalidStartingBlock(BlockId::Hash(block_at)))?;
|
||||
.ok_or_else(|| Error::InvalidStartingBlock(BlockId::Hash(block_at)))?;
|
||||
let state_root = start_header.state_root();
|
||||
let number = start_header.number();
|
||||
|
||||
@@ -512,7 +512,7 @@ fn rebuild_accounts(
|
||||
// fill out the storage trie and code while decoding.
|
||||
let (acc, maybe_code) = {
|
||||
let mut acct_db = AccountDBMut::from_hash(db, hash);
|
||||
let storage_root = known_storage_roots.get(&hash).cloned().unwrap_or(H256::zero());
|
||||
let storage_root = known_storage_roots.get(&hash).cloned().unwrap_or_default();
|
||||
account::from_fat_rlp(&mut acct_db, fat_rlp, storage_root)?
|
||||
};
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ use vm::{EnvInfo, CallType, ActionValue, ActionParams, ParamsType};
|
||||
|
||||
use builtin::Builtin;
|
||||
use engines::{
|
||||
EthEngine, NullEngine, InstantSeal, InstantSealParams, BasicAuthority,
|
||||
EthEngine, NullEngine, InstantSeal, InstantSealParams, BasicAuthority, Clique,
|
||||
AuthorityRound, DEFAULT_BLOCKHASH_CONTRACT
|
||||
};
|
||||
use error::Error;
|
||||
@@ -99,9 +99,9 @@ pub struct CommonParams {
|
||||
pub validate_receipts_transition: BlockNumber,
|
||||
/// Validate transaction chain id.
|
||||
pub validate_chain_id_transition: BlockNumber,
|
||||
/// Number of first block where EIP-140 (Metropolis: REVERT opcode) rules begin.
|
||||
/// Number of first block where EIP-140 rules begin.
|
||||
pub eip140_transition: BlockNumber,
|
||||
/// Number of first block where EIP-210 (Metropolis: BLOCKHASH changes) rules begin.
|
||||
/// Number of first block where EIP-210 rules begin.
|
||||
pub eip210_transition: BlockNumber,
|
||||
/// EIP-210 Blockhash contract address.
|
||||
pub eip210_contract_address: Address,
|
||||
@@ -109,8 +109,7 @@ pub struct CommonParams {
|
||||
pub eip210_contract_code: Bytes,
|
||||
/// Gas allocated for EIP-210 blockhash update.
|
||||
pub eip210_contract_gas: U256,
|
||||
/// Number of first block where EIP-211 (Metropolis: RETURNDATASIZE/RETURNDATACOPY) rules
|
||||
/// begin.
|
||||
/// Number of first block where EIP-211 rules begin.
|
||||
pub eip211_transition: BlockNumber,
|
||||
/// Number of first block where EIP-214 rules begin.
|
||||
pub eip214_transition: BlockNumber,
|
||||
@@ -515,7 +514,7 @@ fn load_from(spec_params: SpecParams, s: ethjson::spec::Spec) -> Result<Spec, Er
|
||||
chts: s.hardcoded_sync
|
||||
.as_ref()
|
||||
.map(|s| s.chts.iter().map(|c| c.clone().into()).collect())
|
||||
.unwrap_or(Vec::new()),
|
||||
.unwrap_or_default()
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@@ -611,6 +610,8 @@ impl Spec {
|
||||
ethjson::spec::Engine::InstantSeal(Some(instant_seal)) => Arc::new(InstantSeal::new(instant_seal.params.into(), machine)),
|
||||
ethjson::spec::Engine::InstantSeal(None) => Arc::new(InstantSeal::new(InstantSealParams::default(), machine)),
|
||||
ethjson::spec::Engine::BasicAuthority(basic_authority) => Arc::new(BasicAuthority::new(basic_authority.params.into(), machine)),
|
||||
ethjson::spec::Engine::Clique(clique) => Clique::new(clique.params.into(), machine)
|
||||
.expect("Failed to start Clique consensus engine."),
|
||||
ethjson::spec::Engine::AuthorityRound(authority_round) => AuthorityRound::new(authority_round.params.into(), machine)
|
||||
.expect("Failed to start AuthorityRound consensus engine."),
|
||||
}
|
||||
@@ -827,7 +828,6 @@ impl Spec {
|
||||
ethjson::spec::Spec::load(reader)
|
||||
.map_err(fmt_err)
|
||||
.map(load_machine_from)
|
||||
|
||||
}
|
||||
|
||||
/// Loads spec from json file. Provide factories for executing contracts and ensuring
|
||||
@@ -999,7 +999,6 @@ mod tests {
|
||||
use types::view;
|
||||
use types::views::BlockView;
|
||||
|
||||
// https://github.com/paritytech/parity-ethereum/issues/1840
|
||||
#[test]
|
||||
fn test_load_empty() {
|
||||
let tempdir = TempDir::new("").unwrap();
|
||||
|
||||
@@ -741,11 +741,4 @@ mod tests {
|
||||
assert_eq!(a.code_hash(), KECCAK_EMPTY);
|
||||
assert_eq!(a.storage_root().unwrap(), KECCAK_NULL_RLP);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_account() {
|
||||
let a = Account::new(69u8.into(), 0u8.into(), HashMap::new(), Bytes::new());
|
||||
assert_eq!(a.rlp().to_hex(), "f8448045a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -82,8 +82,8 @@ pub enum ProvedExecution {
|
||||
BadProof,
|
||||
/// The transaction failed, but not due to a bad proof.
|
||||
Failed(ExecutionError),
|
||||
/// The transaction successfully completd with the given proof.
|
||||
Complete(Executed),
|
||||
/// The transaction successfully completed with the given proof.
|
||||
Complete(Box<Executed>),
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Clone, Copy, Debug)]
|
||||
@@ -218,7 +218,7 @@ pub fn check_proof(
|
||||
|
||||
let options = TransactOptions::with_no_tracing().save_output_from_contract();
|
||||
match state.execute(env_info, machine, transaction, options, true) {
|
||||
Ok(executed) => ProvedExecution::Complete(executed),
|
||||
Ok(executed) => ProvedExecution::Complete(Box::new(executed)),
|
||||
Err(ExecutionError::Internal(_)) => ProvedExecution::BadProof,
|
||||
Err(e) => ProvedExecution::Failed(e),
|
||||
}
|
||||
@@ -1020,7 +1020,7 @@ impl<B: Backend> State<B> {
|
||||
let trie = self.factories.trie.readonly(accountdb, &root)?;
|
||||
for o_kv in trie.iter()? {
|
||||
if let Ok((key, val)) = o_kv {
|
||||
pod_storage.insert(key[..].into(), U256::from(&val[..]).into());
|
||||
pod_storage.insert(key[..].into(), rlp::decode::<U256>(&val[..]).expect("Decoded from trie which was encoded from the same type; qed").into());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1254,7 +1254,7 @@ impl<B: Backend> State<B> {
|
||||
let trie = TrieDB::new(db, &self.root)?;
|
||||
let maybe_account: Option<BasicAccount> = {
|
||||
let panicky_decoder = |bytes: &[u8]| {
|
||||
::rlp::decode(bytes).expect(&format!("prove_account, could not query trie for account key={}", &account_key))
|
||||
::rlp::decode(bytes).unwrap_or_else(|_| panic!("prove_account, could not query trie for account key={}", &account_key))
|
||||
};
|
||||
let query = (&mut recorder, panicky_decoder);
|
||||
trie.get_with(&account_key, query)?
|
||||
|
||||
@@ -155,7 +155,7 @@ pub fn generate_dummy_client_with_spec_and_data<F>(test_spec: F, block_number: u
|
||||
(3141562.into(), 31415620.into()),
|
||||
vec![],
|
||||
false,
|
||||
&mut Vec::new().into_iter(),
|
||||
None,
|
||||
).unwrap();
|
||||
rolling_timestamp += 10;
|
||||
b.set_timestamp(rolling_timestamp);
|
||||
|
||||
@@ -27,7 +27,6 @@ use types::filter::Filter;
|
||||
use types::view;
|
||||
use types::views::BlockView;
|
||||
|
||||
use block::IsBlock;
|
||||
use client::{BlockChainClient, Client, ClientConfig, BlockId, ChainInfo, BlockInfo, PrepareOpenBlock, ImportSealedBlock, ImportBlock};
|
||||
use ethereum;
|
||||
use executive::{Executive, TransactOptions};
|
||||
@@ -254,7 +253,7 @@ fn can_mine() {
|
||||
|
||||
let b = client.prepare_open_block(Address::default(), (3141562.into(), 31415620.into()), vec![]).unwrap().close().unwrap();
|
||||
|
||||
assert_eq!(*b.block().header().parent_hash(), view!(BlockView, &dummy_blocks[0]).header_view().hash());
|
||||
assert_eq!(*b.header.parent_hash(), view!(BlockView, &dummy_blocks[0]).header_view().hash());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -86,7 +86,7 @@ fn can_trace_block_and_uncle_reward() {
|
||||
(3141562.into(), 31415620.into()),
|
||||
vec![],
|
||||
false,
|
||||
&mut Vec::new().into_iter(),
|
||||
None,
|
||||
).unwrap();
|
||||
rolling_timestamp += 10;
|
||||
root_block.set_timestamp(rolling_timestamp);
|
||||
@@ -115,7 +115,7 @@ fn can_trace_block_and_uncle_reward() {
|
||||
(3141562.into(), 31415620.into()),
|
||||
vec![],
|
||||
false,
|
||||
&mut Vec::new().into_iter(),
|
||||
None,
|
||||
).unwrap();
|
||||
rolling_timestamp += 10;
|
||||
parent_block.set_timestamp(rolling_timestamp);
|
||||
@@ -143,7 +143,7 @@ fn can_trace_block_and_uncle_reward() {
|
||||
(3141562.into(), 31415620.into()),
|
||||
vec![],
|
||||
false,
|
||||
&mut Vec::new().into_iter(),
|
||||
None,
|
||||
).unwrap();
|
||||
rolling_timestamp += 10;
|
||||
block.set_timestamp(rolling_timestamp);
|
||||
|
||||
@@ -135,7 +135,7 @@ impl Create {
|
||||
}
|
||||
|
||||
/// Reward type.
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub enum RewardType {
|
||||
/// Block
|
||||
Block,
|
||||
|
||||
@@ -34,30 +34,14 @@ use unexpected::{Mismatch, OutOfBounds};
|
||||
use blockchain::*;
|
||||
use call_contract::CallContract;
|
||||
use client::BlockInfo;
|
||||
use engines::EthEngine;
|
||||
use engines::{EthEngine, MAX_UNCLE_AGE};
|
||||
use error::{BlockError, Error};
|
||||
use types::{BlockNumber, header::Header};
|
||||
use types::transaction::SignedTransaction;
|
||||
use verification::queue::kind::blocks::Unverified;
|
||||
|
||||
|
||||
/// Returns `Ok<SystemTime>` when the result less or equal to `i32::max_value` to prevent `SystemTime` to panic because
|
||||
/// it is platform specific, may be i32 or i64.
|
||||
///
|
||||
/// `Err<BlockError::TimestampOver` otherwise.
|
||||
///
|
||||
// FIXME: @niklasad1 - remove this when and use `SystemTime::checked_add`
|
||||
// when https://github.com/rust-lang/rust/issues/55940 is stabilized.
|
||||
fn timestamp_checked_add(sys: SystemTime, d2: Duration) -> Result<SystemTime, BlockError> {
|
||||
let d1 = sys.duration_since(UNIX_EPOCH).map_err(|_| BlockError::TimestampOverflow)?;
|
||||
let total_time = d1.checked_add(d2).ok_or(BlockError::TimestampOverflow)?;
|
||||
|
||||
if total_time.as_secs() <= i32::max_value() as u64 {
|
||||
Ok(sys + d2)
|
||||
} else {
|
||||
Err(BlockError::TimestampOverflow)
|
||||
}
|
||||
}
|
||||
#[cfg(not(time_checked_add))]
|
||||
use time_utils::CheckedSystemTime;
|
||||
|
||||
/// Preprocessed block data gathered in `verify_block_unordered` call
|
||||
pub struct PreverifiedBlock {
|
||||
@@ -192,7 +176,7 @@ fn verify_uncles(block: &PreverifiedBlock, bc: &BlockProvider, engine: &EthEngin
|
||||
excluded.insert(header.hash());
|
||||
let mut hash = header.parent_hash().clone();
|
||||
excluded.insert(hash.clone());
|
||||
for _ in 0..engine.maximum_uncle_age() {
|
||||
for _ in 0..MAX_UNCLE_AGE {
|
||||
match bc.block_details(&hash) {
|
||||
Some(details) => {
|
||||
excluded.insert(details.parent);
|
||||
@@ -225,7 +209,7 @@ fn verify_uncles(block: &PreverifiedBlock, bc: &BlockProvider, engine: &EthEngin
|
||||
// (8 Invalid)
|
||||
|
||||
let depth = if header.number() > uncle.number() { header.number() - uncle.number() } else { 0 };
|
||||
if depth > engine.maximum_uncle_age() as u64 {
|
||||
if depth > MAX_UNCLE_AGE as u64 {
|
||||
return Err(From::from(BlockError::UncleTooOld(OutOfBounds { min: Some(header.number() - depth), max: Some(header.number() - 1), found: uncle.number() })));
|
||||
}
|
||||
else if depth < 1 {
|
||||
@@ -274,7 +258,7 @@ pub fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error>
|
||||
return Err(From::from(BlockError::InvalidGasUsed(Mismatch { expected: *expected.gas_used(), found: *got.gas_used() })))
|
||||
}
|
||||
if expected.log_bloom() != got.log_bloom() {
|
||||
return Err(From::from(BlockError::InvalidLogBloom(Mismatch { expected: *expected.log_bloom(), found: *got.log_bloom() })))
|
||||
return Err(From::from(BlockError::InvalidLogBloom(Box::new(Mismatch { expected: *expected.log_bloom(), found: *got.log_bloom() }))))
|
||||
}
|
||||
if expected.receipts_root() != got.receipts_root() {
|
||||
return Err(From::from(BlockError::InvalidReceiptsRoot(Mismatch { expected: *expected.receipts_root(), found: *got.receipts_root() })))
|
||||
@@ -323,9 +307,11 @@ pub fn verify_header_params(header: &Header, engine: &EthEngine, is_full: bool,
|
||||
|
||||
if is_full {
|
||||
const ACCEPTABLE_DRIFT: Duration = Duration::from_secs(15);
|
||||
// this will resist overflow until `year 2037`
|
||||
let max_time = SystemTime::now() + ACCEPTABLE_DRIFT;
|
||||
let invalid_threshold = max_time + ACCEPTABLE_DRIFT * 9;
|
||||
let timestamp = timestamp_checked_add(UNIX_EPOCH, Duration::from_secs(header.timestamp()))?;
|
||||
let timestamp = UNIX_EPOCH.checked_add(Duration::from_secs(header.timestamp()))
|
||||
.ok_or(BlockError::TimestampOverflow)?;
|
||||
|
||||
if timestamp > invalid_threshold {
|
||||
return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: Some(max_time), min: None, found: timestamp })))
|
||||
@@ -347,8 +333,11 @@ fn verify_parent(header: &Header, parent: &Header, engine: &EthEngine) -> Result
|
||||
let gas_limit_divisor = engine.params().gas_limit_bound_divisor;
|
||||
|
||||
if !engine.is_timestamp_valid(header.timestamp(), parent.timestamp()) {
|
||||
let min = timestamp_checked_add(SystemTime::now(), Duration::from_secs(parent.timestamp().saturating_add(1)))?;
|
||||
let found = timestamp_checked_add(SystemTime::now(), Duration::from_secs(header.timestamp()))?;
|
||||
let now = SystemTime::now();
|
||||
let min = now.checked_add(Duration::from_secs(parent.timestamp().saturating_add(1)))
|
||||
.ok_or(BlockError::TimestampOverflow)?;
|
||||
let found = now.checked_add(Duration::from_secs(header.timestamp()))
|
||||
.ok_or(BlockError::TimestampOverflow)?;
|
||||
return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: None, min: Some(min), found })))
|
||||
}
|
||||
if header.number() != parent.number() + 1 {
|
||||
@@ -835,11 +824,4 @@ mod tests {
|
||||
check_fail(unordered_test(&create_test_block_with_data(&header, &bad_transactions, &[]), &engine), TooManyTransactions(keypair.address()));
|
||||
unordered_test(&create_test_block_with_data(&header, &good_transactions, &[]), &engine).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checked_add_systime_dur() {
|
||||
assert!(timestamp_checked_add(UNIX_EPOCH, Duration::new(i32::max_value() as u64 + 1, 0)).is_err());
|
||||
assert!(timestamp_checked_add(UNIX_EPOCH, Duration::new(i32::max_value() as u64, 0)).is_ok());
|
||||
assert!(timestamp_checked_add(UNIX_EPOCH, Duration::new(i32::max_value() as u64 - 1, 1_000_000_000)).is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ ethkey = { path = "../../accounts/ethkey" }
|
||||
heapsize = "0.4"
|
||||
keccak-hash = "0.1"
|
||||
parity-bytes = "0.1"
|
||||
parity-machine = { path = "../../machine" }
|
||||
rlp = { version = "0.3.0", features = ["ethereum"] }
|
||||
rlp_derive = { path = "../../util/rlp-derive" }
|
||||
unexpected = { path = "../../util/unexpected" }
|
||||
|
||||
@@ -71,28 +71,3 @@ impl Decodable for PendingTransition {
|
||||
}
|
||||
}
|
||||
|
||||
/// Verifier for all blocks within an epoch with self-contained state.
|
||||
pub trait EpochVerifier<M: ::parity_machine::Machine>: Send + Sync {
|
||||
/// Lightly verify the next block header.
|
||||
/// This may not be a header belonging to a different epoch.
|
||||
fn verify_light(&self, header: &M::Header) -> Result<(), M::Error>;
|
||||
|
||||
/// Perform potentially heavier checks on the next block header.
|
||||
fn verify_heavy(&self, header: &M::Header) -> Result<(), M::Error> {
|
||||
self.verify_light(header)
|
||||
}
|
||||
|
||||
/// Check a finality proof against this epoch verifier.
|
||||
/// Returns `Some(hashes)` if the proof proves finality of these hashes.
|
||||
/// Returns `None` if the proof doesn't prove anything.
|
||||
fn check_finality_proof(&self, _proof: &[u8]) -> Option<Vec<H256>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Special "no-op" verifier for stateless, epoch-less engines.
|
||||
pub struct NoOp;
|
||||
|
||||
impl<M: ::parity_machine::Machine> EpochVerifier<M> for NoOp {
|
||||
fn verify_light(&self, _header: &M::Header) -> Result<(), M::Error> { Ok(()) }
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
@@ -368,44 +367,11 @@ impl HeapSizeOf for Header {
|
||||
}
|
||||
}
|
||||
|
||||
impl ::parity_machine::Header for Header {
|
||||
fn bare_hash(&self) -> H256 { Header::bare_hash(self) }
|
||||
fn hash(&self) -> H256 { Header::hash(self) }
|
||||
fn seal(&self) -> &[Vec<u8>] { Header::seal(self) }
|
||||
fn author(&self) -> &Address { Header::author(self) }
|
||||
fn number(&self) -> BlockNumber { Header::number(self) }
|
||||
}
|
||||
|
||||
impl ::parity_machine::ScoredHeader for Header {
|
||||
type Value = U256;
|
||||
|
||||
fn score(&self) -> &U256 { self.difficulty() }
|
||||
fn set_score(&mut self, score: U256) { self.set_difficulty(score) }
|
||||
}
|
||||
|
||||
impl ::parity_machine::Header for ExtendedHeader {
|
||||
fn bare_hash(&self) -> H256 { self.header.bare_hash() }
|
||||
fn hash(&self) -> H256 { self.header.hash() }
|
||||
fn seal(&self) -> &[Vec<u8>] { self.header.seal() }
|
||||
fn author(&self) -> &Address { self.header.author() }
|
||||
fn number(&self) -> BlockNumber { self.header.number() }
|
||||
}
|
||||
|
||||
impl ::parity_machine::ScoredHeader for ExtendedHeader {
|
||||
type Value = U256;
|
||||
|
||||
fn score(&self) -> &U256 { self.header.difficulty() }
|
||||
fn set_score(&mut self, score: U256) { self.header.set_difficulty(score) }
|
||||
}
|
||||
|
||||
impl ::parity_machine::TotalScoredHeader for ExtendedHeader {
|
||||
type Value = U256;
|
||||
|
||||
fn total_score(&self) -> U256 { self.parent_total_difficulty + *self.header.difficulty() }
|
||||
}
|
||||
|
||||
impl ::parity_machine::FinalizableHeader for ExtendedHeader {
|
||||
fn is_finalized(&self) -> bool { self.is_finalized }
|
||||
impl ExtendedHeader {
|
||||
/// Returns combined difficulty of all ancestors together with the difficulty of this header.
|
||||
pub fn total_score(&self) -> U256 {
|
||||
self.parent_total_difficulty + *self.header.difficulty()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -445,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
//! Unique identifiers.
|
||||
|
||||
use ethereum_types::H256;
|
||||
use {BlockNumber};
|
||||
use BlockNumber;
|
||||
|
||||
/// Uniquely identifies block.
|
||||
#[derive(Debug, PartialEq, Copy, Clone, Hash, Eq)]
|
||||
|
||||
@@ -39,7 +39,6 @@ extern crate ethkey;
|
||||
extern crate heapsize;
|
||||
extern crate keccak_hash as hash;
|
||||
extern crate parity_bytes as bytes;
|
||||
extern crate parity_machine;
|
||||
extern crate rlp;
|
||||
extern crate unexpected;
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
use std::time::{Instant, Duration};
|
||||
use ethereum_types::{H256, U256};
|
||||
use ethcore::client::{self, EvmTestClient, EvmTestError, TransactResult};
|
||||
use ethcore::client::{self, EvmTestClient, EvmTestError, TransactErr, TransactSuccess};
|
||||
use ethcore::{state, state_db, trace, spec, pod_state, TrieSpec};
|
||||
use ethjson;
|
||||
use types::transaction;
|
||||
@@ -130,7 +130,7 @@ pub fn run_transaction<T: Informant>(
|
||||
let result = run(&spec, trie_spec, transaction.gas, pre_state, |mut client| {
|
||||
let result = client.transact(env_info, transaction, trace::NoopTracer, informant);
|
||||
match result {
|
||||
TransactResult::Ok { state_root, gas_left, output, vm_trace, end_state, .. } => {
|
||||
Ok(TransactSuccess { state_root, gas_left, output, vm_trace, end_state, .. }) => {
|
||||
if state_root != post_root {
|
||||
(Err(EvmTestError::PostCondition(format!(
|
||||
"State root mismatch (got: {:#x}, expected: {:#x})",
|
||||
@@ -141,7 +141,7 @@ pub fn run_transaction<T: Informant>(
|
||||
(Ok(output), state_root, end_state, Some(gas_left), vm_trace)
|
||||
}
|
||||
},
|
||||
TransactResult::Err { state_root, error, end_state } => {
|
||||
Err(TransactErr { state_root, error, end_state }) => {
|
||||
(Err(EvmTestError::PostCondition(format!(
|
||||
"Unexpected execution error: {:?}", error
|
||||
))), state_root, end_state, None, None)
|
||||
|
||||
57
json/src/spec/clique.rs
Normal file
57
json/src/spec/clique.rs
Normal file
@@ -0,0 +1,57 @@
|
||||
// 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/>.
|
||||
|
||||
//! Clique params deserialization.
|
||||
|
||||
use std::num::NonZeroU64;
|
||||
|
||||
/// Clique params deserialization.
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
pub struct CliqueParams {
|
||||
/// period as defined in EIP
|
||||
pub period: Option<u64>,
|
||||
/// epoch length as defined in EIP
|
||||
pub epoch: Option<NonZeroU64>
|
||||
}
|
||||
|
||||
/// Clique engine deserialization.
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
pub struct Clique {
|
||||
/// CliqueEngine params
|
||||
pub params: CliqueParams,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json;
|
||||
use uint::Uint;
|
||||
use ethereum_types::U256;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn clique_deserialization() {
|
||||
let s = r#"{
|
||||
"params": {
|
||||
"period": 5,
|
||||
"epoch": 30000
|
||||
}
|
||||
}"#;
|
||||
|
||||
let deserialized: Clique = serde_json::from_str(s).unwrap();
|
||||
assert_eq!(deserialized.params.period, Some(5u64));
|
||||
assert_eq!(deserialized.params.epoch, NonZeroU64::new(30000));
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
//! Engine deserialization.
|
||||
|
||||
use super::{Ethash, BasicAuthority, AuthorityRound, NullEngine, InstantSeal};
|
||||
use super::{Ethash, BasicAuthority, AuthorityRound, NullEngine, InstantSeal, Clique};
|
||||
|
||||
/// Engine deserialization.
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
@@ -34,6 +34,8 @@ pub enum Engine {
|
||||
BasicAuthority(BasicAuthority),
|
||||
/// AuthorityRound engine.
|
||||
AuthorityRound(AuthorityRound),
|
||||
/// Clique engine.
|
||||
Clique(Clique)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -130,5 +132,19 @@ mod tests {
|
||||
Engine::AuthorityRound(_) => {}, // AuthorityRound is unit tested in its own file.
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
let s = r#"{
|
||||
"clique": {
|
||||
"params": {
|
||||
"period": 15,
|
||||
"epoch": 30000
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
let deserialized: Engine = serde_json::from_str(s).unwrap();
|
||||
match deserialized {
|
||||
Engine::Clique(_) => {}, // Clique is unit tested in its own file.
|
||||
_ => panic!(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ pub mod authority_round;
|
||||
pub mod null_engine;
|
||||
pub mod instant_seal;
|
||||
pub mod hardcoded_sync;
|
||||
pub mod clique;
|
||||
|
||||
pub use self::account::Account;
|
||||
pub use self::builtin::{Builtin, Pricing, Linear};
|
||||
@@ -44,6 +45,7 @@ pub use self::ethash::{Ethash, EthashParams, BlockReward};
|
||||
pub use self::validator_set::ValidatorSet;
|
||||
pub use self::basic_authority::{BasicAuthority, BasicAuthorityParams};
|
||||
pub use self::authority_round::{AuthorityRound, AuthorityRoundParams};
|
||||
pub use self::clique::{Clique, CliqueParams};
|
||||
pub use self::null_engine::{NullEngine, NullEngineParams};
|
||||
pub use self::instant_seal::{InstantSeal, InstantSealParams};
|
||||
pub use self::hardcoded_sync::HardcodedSync;
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
[package]
|
||||
name = "parity-machine"
|
||||
version = "0.1.0"
|
||||
description = "Generalization of a state machine for consensus engines"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[dependencies]
|
||||
ethereum-types = "0.4"
|
||||
@@ -1,132 +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/>.
|
||||
|
||||
//! Generalization of a state machine for a consensus engine.
|
||||
//! This will define traits for the header, block, and state of a blockchain.
|
||||
|
||||
extern crate ethereum_types;
|
||||
|
||||
use ethereum_types::{H256, U256, Address};
|
||||
|
||||
/// A header. This contains important metadata about the block, as well as a
|
||||
/// "seal" that indicates validity to a consensus engine.
|
||||
pub trait Header {
|
||||
/// Cryptographic hash of the header, excluding the seal.
|
||||
fn bare_hash(&self) -> H256;
|
||||
|
||||
/// Cryptographic hash of the header, including the seal.
|
||||
fn hash(&self) -> H256;
|
||||
|
||||
/// Get a reference to the seal fields.
|
||||
fn seal(&self) -> &[Vec<u8>];
|
||||
|
||||
/// The author of the header.
|
||||
fn author(&self) -> &Address;
|
||||
|
||||
/// The number of the header.
|
||||
fn number(&self) -> u64;
|
||||
}
|
||||
|
||||
/// A header with an associated score (difficulty in PoW terms)
|
||||
pub trait ScoredHeader: Header {
|
||||
type Value;
|
||||
|
||||
/// Get the score of this header.
|
||||
fn score(&self) -> &Self::Value;
|
||||
|
||||
/// Set the score of this header.
|
||||
fn set_score(&mut self, score: Self::Value);
|
||||
}
|
||||
|
||||
/// A header with associated total score.
|
||||
pub trait TotalScoredHeader: Header {
|
||||
type Value;
|
||||
|
||||
/// Get the total score of this header.
|
||||
fn total_score(&self) -> Self::Value;
|
||||
}
|
||||
|
||||
/// A header with finalized information.
|
||||
pub trait FinalizableHeader: Header {
|
||||
/// Get whether this header is considered finalized, so that it will never be replaced in reorganization.
|
||||
fn is_finalized(&self) -> bool;
|
||||
}
|
||||
|
||||
/// A header with metadata information.
|
||||
pub trait WithMetadataHeader: Header {
|
||||
/// Get the current header metadata.
|
||||
fn metadata(&self) -> Option<&[u8]>;
|
||||
}
|
||||
|
||||
/// A "live" block is one which is in the process of the transition.
|
||||
/// The state of this block can be mutated by arbitrary rules of the
|
||||
/// state transition function.
|
||||
pub trait LiveBlock: 'static {
|
||||
/// The block header type;
|
||||
type Header: Header;
|
||||
|
||||
/// Get a reference to the header.
|
||||
fn header(&self) -> &Self::Header;
|
||||
|
||||
/// Get a reference to the uncle headers. If the block type doesn't
|
||||
/// support uncles, return the empty slice.
|
||||
fn uncles(&self) -> &[Self::Header];
|
||||
}
|
||||
|
||||
/// Trait for blocks which have a transaction type.
|
||||
pub trait Transactions: LiveBlock {
|
||||
/// The transaction type.
|
||||
type Transaction;
|
||||
|
||||
/// Get a reference to the transactions in this block.
|
||||
fn transactions(&self) -> &[Self::Transaction];
|
||||
}
|
||||
|
||||
/// Generalization of types surrounding blockchain-suitable state machines.
|
||||
pub trait Machine: for<'a> LocalizedMachine<'a> {
|
||||
/// The block header type.
|
||||
type Header: Header;
|
||||
/// The live block type.
|
||||
type LiveBlock: LiveBlock<Header=Self::Header>;
|
||||
/// Block header with metadata information.
|
||||
type ExtendedHeader: Header;
|
||||
/// A handle to a blockchain client for this machine.
|
||||
type EngineClient: ?Sized;
|
||||
/// A description of needed auxiliary data.
|
||||
type AuxiliaryRequest;
|
||||
/// Actions taken on ancestry blocks when commiting a new block.
|
||||
type AncestryAction;
|
||||
|
||||
/// Errors which can occur when querying or interacting with the machine.
|
||||
type Error;
|
||||
|
||||
/// Get the balance, in base units, associated with an account.
|
||||
/// Extracts data from the live block.
|
||||
fn balance(&self, live: &Self::LiveBlock, address: &Address) -> Result<U256, Self::Error>;
|
||||
|
||||
/// Increment the balance of an account in the state of the live block.
|
||||
fn add_balance(&self, live: &mut Self::LiveBlock, address: &Address, amount: &U256) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
/// Machine-related types localized to a specific lifetime.
|
||||
// TODO: this is a workaround for a lack of associated type constructors in the language.
|
||||
pub trait LocalizedMachine<'a>: Sync + Send {
|
||||
/// Definition of auxiliary data associated to a specific block.
|
||||
type AuxiliaryData: 'a;
|
||||
/// A context providing access to the state in a controlled capacity.
|
||||
/// Generally also provides verifiable proofs.
|
||||
type StateContext: ?Sized + 'a;
|
||||
}
|
||||
@@ -32,7 +32,7 @@ parking_lot = "0.7"
|
||||
price-info = { path = "./price-info", optional = true }
|
||||
rlp = { version = "0.3.0", features = ["ethereum"] }
|
||||
trace-time = "0.1"
|
||||
transaction-pool = "1.13"
|
||||
transaction-pool = "2.0"
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.5"
|
||||
|
||||
@@ -92,7 +92,7 @@ impl txpool::Listener<Transaction> for Logger {
|
||||
}
|
||||
}
|
||||
|
||||
fn rejected(&mut self, _tx: &Arc<Transaction>, reason: &txpool::ErrorKind) {
|
||||
fn rejected<H: fmt::Debug + fmt::LowerHex>(&mut self, _tx: &Arc<Transaction>, reason: &txpool::Error<H>) {
|
||||
trace!(target: "txqueue", "Rejected {}.", reason);
|
||||
}
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ impl txpool::Listener<Transaction> for LocalTransactionsList {
|
||||
}
|
||||
}
|
||||
|
||||
fn rejected(&mut self, tx: &Arc<Transaction>, reason: &txpool::ErrorKind) {
|
||||
fn rejected<H: fmt::Debug + fmt::LowerHex>(&mut self, tx: &Arc<Transaction>, reason: &txpool::Error<H>) {
|
||||
if !tx.priority().is_local() {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ mod ready;
|
||||
|
||||
pub mod client;
|
||||
pub mod local_transactions;
|
||||
pub mod replace;
|
||||
pub mod scoring;
|
||||
pub mod verifier;
|
||||
|
||||
@@ -121,7 +122,7 @@ pub trait ScoredTransaction {
|
||||
}
|
||||
|
||||
/// Verified transaction stored in the pool.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct VerifiedTransaction {
|
||||
transaction: transaction::PendingTransaction,
|
||||
// TODO [ToDr] hash and sender should go directly from the transaction
|
||||
|
||||
@@ -27,7 +27,7 @@ use txpool::{self, Verifier};
|
||||
use types::transaction;
|
||||
|
||||
use pool::{
|
||||
self, scoring, verifier, client, ready, listener,
|
||||
self, replace, scoring, verifier, client, ready, listener,
|
||||
PrioritizationStrategy, PendingOrdering, PendingSettings,
|
||||
};
|
||||
use pool::local_transactions::LocalTransactionsList;
|
||||
@@ -240,7 +240,7 @@ impl TransactionQueue {
|
||||
///
|
||||
/// Given blockchain and state access (Client)
|
||||
/// verifies and imports transactions to the pool.
|
||||
pub fn import<C: client::Client>(
|
||||
pub fn import<C: client::Client + client::NonceClient + Clone>(
|
||||
&self,
|
||||
client: C,
|
||||
transactions: Vec<verifier::Transaction>,
|
||||
@@ -263,12 +263,14 @@ impl TransactionQueue {
|
||||
};
|
||||
|
||||
let verifier = verifier::Verifier::new(
|
||||
client,
|
||||
client.clone(),
|
||||
options,
|
||||
self.insertion_id.clone(),
|
||||
transaction_to_replace,
|
||||
);
|
||||
|
||||
let mut replace = replace::ReplaceByScoreAndReadiness::new(self.pool.read().scoring().clone(), client);
|
||||
|
||||
let results = transactions
|
||||
.into_iter()
|
||||
.map(|transaction| {
|
||||
@@ -286,7 +288,7 @@ impl TransactionQueue {
|
||||
let imported = verifier
|
||||
.verify_transaction(transaction)
|
||||
.and_then(|verified| {
|
||||
self.pool.write().import(verified).map_err(convert_error)
|
||||
self.pool.write().import(verified, &mut replace).map_err(convert_error)
|
||||
});
|
||||
|
||||
match imported {
|
||||
@@ -579,17 +581,13 @@ impl TransactionQueue {
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_error(err: txpool::Error) -> transaction::Error {
|
||||
use self::txpool::ErrorKind;
|
||||
fn convert_error<H: fmt::Debug + fmt::LowerHex>(err: txpool::Error<H>) -> transaction::Error {
|
||||
use self::txpool::Error;
|
||||
|
||||
match *err.kind() {
|
||||
ErrorKind::AlreadyImported(..) => transaction::Error::AlreadyImported,
|
||||
ErrorKind::TooCheapToEnter(..) => transaction::Error::LimitReached,
|
||||
ErrorKind::TooCheapToReplace(..) => transaction::Error::TooCheapToReplace,
|
||||
ref e => {
|
||||
warn!(target: "txqueue", "Unknown import error: {:?}", e);
|
||||
transaction::Error::NotAllowed
|
||||
},
|
||||
match err {
|
||||
Error::AlreadyImported(..) => transaction::Error::AlreadyImported,
|
||||
Error::TooCheapToEnter(..) => transaction::Error::LimitReached,
|
||||
Error::TooCheapToReplace(..) => transaction::Error::TooCheapToReplace
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
415
miner/src/pool/replace.rs
Normal file
415
miner/src/pool/replace.rs
Normal file
@@ -0,0 +1,415 @@
|
||||
// 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/>.
|
||||
|
||||
//! Replacing Transactions
|
||||
//!
|
||||
//! When queue limits are reached, a new transaction may replace one already
|
||||
//! in the pool. The decision whether to reject, replace or retain both is
|
||||
//! delegated to an implementation of `ShouldReplace`.
|
||||
//!
|
||||
//! Here we decide based on the sender, the nonce and gas price, and finally
|
||||
//! on the `Readiness` of the transactions when comparing them
|
||||
|
||||
use std::cmp;
|
||||
|
||||
use ethereum_types::{U256, H160 as Address};
|
||||
use txpool::{self, scoring::{Choice, Scoring}, ReplaceTransaction};
|
||||
use txpool::VerifiedTransaction;
|
||||
use super::{client, ScoredTransaction};
|
||||
|
||||
/// Choose whether to replace based on the sender, the score and finally the
|
||||
/// `Readiness` of the transactions being compared.
|
||||
#[derive(Debug)]
|
||||
pub struct ReplaceByScoreAndReadiness<S, C> {
|
||||
scoring: S,
|
||||
client: C,
|
||||
}
|
||||
|
||||
impl<S, C> ReplaceByScoreAndReadiness<S, C> {
|
||||
/// Create a new `ReplaceByScoreAndReadiness`
|
||||
pub fn new(scoring: S, client: C) -> Self {
|
||||
ReplaceByScoreAndReadiness { scoring, client }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, C> txpool::ShouldReplace<T> for ReplaceByScoreAndReadiness<S, C>
|
||||
where
|
||||
T: VerifiedTransaction<Sender = Address> + ScoredTransaction + PartialEq,
|
||||
S: Scoring<T>,
|
||||
C: client::NonceClient,
|
||||
{
|
||||
fn should_replace(
|
||||
&self,
|
||||
old: &ReplaceTransaction<T>,
|
||||
new: &ReplaceTransaction<T>,
|
||||
) -> Choice {
|
||||
let both_local = old.priority().is_local() && new.priority().is_local();
|
||||
if old.sender() == new.sender() {
|
||||
// prefer earliest transaction
|
||||
match new.nonce().cmp(&old.nonce()) {
|
||||
cmp::Ordering::Equal => self.scoring.choose(&old, &new),
|
||||
_ if both_local => Choice::InsertNew,
|
||||
cmp::Ordering::Less => Choice::ReplaceOld,
|
||||
cmp::Ordering::Greater => Choice::RejectNew,
|
||||
}
|
||||
} else if both_local {
|
||||
Choice::InsertNew
|
||||
} else {
|
||||
let old_score = (old.priority(), old.gas_price());
|
||||
let new_score = (new.priority(), new.gas_price());
|
||||
if new_score > old_score {
|
||||
let state = &self.client;
|
||||
// calculate readiness based on state nonce + pooled txs from same sender
|
||||
let is_ready = |replace: &ReplaceTransaction<T>| {
|
||||
let mut nonce = state.account_nonce(replace.sender());
|
||||
if let Some(txs) = replace.pooled_by_sender {
|
||||
for tx in txs.iter() {
|
||||
if nonce == tx.nonce() && *tx.transaction != ***replace.transaction {
|
||||
nonce = nonce.saturating_add(U256::from(1))
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
nonce == replace.nonce()
|
||||
};
|
||||
|
||||
if !is_ready(new) && is_ready(old) {
|
||||
// prevent a ready transaction being replace by a non-ready transaction
|
||||
Choice::RejectNew
|
||||
} else {
|
||||
Choice::ReplaceOld
|
||||
}
|
||||
} else {
|
||||
Choice::RejectNew
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use std::sync::Arc;
|
||||
use ethkey::{Random, Generator, KeyPair};
|
||||
use pool::tests::tx::{Tx, TxExt};
|
||||
use pool::tests::client::TestClient;
|
||||
use pool::scoring::*;
|
||||
use pool::{PrioritizationStrategy, VerifiedTransaction};
|
||||
use txpool::scoring::Choice::*;
|
||||
use txpool::ShouldReplace;
|
||||
|
||||
fn local_tx_verified(tx: Tx, keypair: &KeyPair) -> VerifiedTransaction {
|
||||
let mut verified_tx = tx.unsigned().sign(keypair.secret(), None).verified();
|
||||
verified_tx.priority = ::pool::Priority::Local;
|
||||
verified_tx
|
||||
}
|
||||
|
||||
fn should_replace(replace: &ShouldReplace<VerifiedTransaction>, old: VerifiedTransaction, new: VerifiedTransaction) -> Choice {
|
||||
let old_tx = txpool::Transaction { insertion_id: 0, transaction: Arc::new(old) };
|
||||
let new_tx = txpool::Transaction { insertion_id: 0, transaction: Arc::new(new) };
|
||||
let old = ReplaceTransaction::new(&old_tx, Default::default());
|
||||
let new = ReplaceTransaction::new(&new_tx, Default::default());
|
||||
replace.should_replace(&old, &new)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_always_accept_local_transactions_unless_same_sender_and_nonce() {
|
||||
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
|
||||
let client = TestClient::new().with_nonce(1);
|
||||
let replace = ReplaceByScoreAndReadiness::new(scoring, client);
|
||||
|
||||
// same sender txs
|
||||
let keypair = Random.generate().unwrap();
|
||||
|
||||
let same_sender_tx1 = local_tx_verified(Tx {
|
||||
nonce: 1,
|
||||
gas_price: 1,
|
||||
..Default::default()
|
||||
}, &keypair);
|
||||
|
||||
let same_sender_tx2 = local_tx_verified(Tx {
|
||||
nonce: 2,
|
||||
gas_price: 100,
|
||||
..Default::default()
|
||||
}, &keypair);
|
||||
|
||||
let same_sender_tx3 = local_tx_verified(Tx {
|
||||
nonce: 2,
|
||||
gas_price: 200,
|
||||
..Default::default()
|
||||
}, &keypair);
|
||||
|
||||
// different sender txs
|
||||
let sender1 = Random.generate().unwrap();
|
||||
let different_sender_tx1 = local_tx_verified(Tx {
|
||||
nonce: 2,
|
||||
gas_price: 1,
|
||||
..Default::default()
|
||||
}, &sender1);
|
||||
|
||||
let sender2 = Random.generate().unwrap();
|
||||
let different_sender_tx2 = local_tx_verified(Tx {
|
||||
nonce: 1,
|
||||
gas_price: 10,
|
||||
..Default::default()
|
||||
}, &sender2);
|
||||
|
||||
assert_eq!(should_replace(&replace, same_sender_tx1.clone(), same_sender_tx2.clone()), InsertNew);
|
||||
assert_eq!(should_replace(&replace, same_sender_tx2.clone(), same_sender_tx1.clone()), InsertNew);
|
||||
|
||||
assert_eq!(should_replace(&replace, different_sender_tx1.clone(), different_sender_tx2.clone()), InsertNew);
|
||||
assert_eq!(should_replace(&replace, different_sender_tx2.clone(), different_sender_tx1.clone()), InsertNew);
|
||||
|
||||
// txs with same sender and nonce
|
||||
assert_eq!(should_replace(&replace, same_sender_tx2.clone(), same_sender_tx3.clone()), ReplaceOld);
|
||||
assert_eq!(should_replace(&replace, same_sender_tx3.clone(), same_sender_tx2.clone()), RejectNew);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_replace_same_sender_by_nonce() {
|
||||
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
|
||||
let client = TestClient::new().with_nonce(1);
|
||||
let replace = ReplaceByScoreAndReadiness::new(scoring, client);
|
||||
|
||||
let tx1 = Tx {
|
||||
nonce: 1,
|
||||
gas_price: 1,
|
||||
..Default::default()
|
||||
};
|
||||
let tx2 = Tx {
|
||||
nonce: 2,
|
||||
gas_price: 100,
|
||||
..Default::default()
|
||||
};
|
||||
let tx3 = Tx {
|
||||
nonce: 2,
|
||||
gas_price: 110,
|
||||
..Default::default()
|
||||
};
|
||||
let tx4 = Tx {
|
||||
nonce: 2,
|
||||
gas_price: 130,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let keypair = Random.generate().unwrap();
|
||||
let txs = vec![tx1, tx2, tx3, tx4].into_iter().map(|tx| {
|
||||
tx.unsigned().sign(keypair.secret(), None).verified()
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(should_replace(&replace, txs[0].clone(), txs[1].clone()), RejectNew);
|
||||
assert_eq!(should_replace(&replace, txs[1].clone(), txs[0].clone()), ReplaceOld);
|
||||
|
||||
assert_eq!(should_replace(&replace, txs[1].clone(), txs[2].clone()), RejectNew);
|
||||
assert_eq!(should_replace(&replace, txs[2].clone(), txs[1].clone()), RejectNew);
|
||||
|
||||
assert_eq!(should_replace(&replace, txs[1].clone(), txs[3].clone()), ReplaceOld);
|
||||
assert_eq!(should_replace(&replace, txs[3].clone(), txs[1].clone()), RejectNew);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_replace_different_sender_by_priority_and_gas_price() {
|
||||
// given
|
||||
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
|
||||
let client = TestClient::new().with_nonce(0);
|
||||
let replace = ReplaceByScoreAndReadiness::new(scoring, client);
|
||||
|
||||
let tx_regular_low_gas = {
|
||||
let tx = Tx {
|
||||
nonce: 1,
|
||||
gas_price: 1,
|
||||
..Default::default()
|
||||
};
|
||||
tx.signed().verified()
|
||||
};
|
||||
let tx_regular_high_gas = {
|
||||
let tx = Tx {
|
||||
nonce: 2,
|
||||
gas_price: 10,
|
||||
..Default::default()
|
||||
};
|
||||
tx.signed().verified()
|
||||
};
|
||||
let tx_local_low_gas = {
|
||||
let tx = Tx {
|
||||
nonce: 2,
|
||||
gas_price: 1,
|
||||
..Default::default()
|
||||
};
|
||||
let mut verified_tx = tx.signed().verified();
|
||||
verified_tx.priority = ::pool::Priority::Local;
|
||||
verified_tx
|
||||
};
|
||||
let tx_local_high_gas = {
|
||||
let tx = Tx {
|
||||
nonce: 1,
|
||||
gas_price: 10,
|
||||
..Default::default()
|
||||
};
|
||||
let mut verified_tx = tx.signed().verified();
|
||||
verified_tx.priority = ::pool::Priority::Local;
|
||||
verified_tx
|
||||
};
|
||||
|
||||
assert_eq!(should_replace(&replace, tx_regular_low_gas.clone(), tx_regular_high_gas.clone()), ReplaceOld);
|
||||
assert_eq!(should_replace(&replace, tx_regular_high_gas.clone(), tx_regular_low_gas.clone()), RejectNew);
|
||||
|
||||
assert_eq!(should_replace(&replace, tx_regular_high_gas.clone(), tx_local_low_gas.clone()), ReplaceOld);
|
||||
assert_eq!(should_replace(&replace, tx_local_low_gas.clone(), tx_regular_high_gas.clone()), RejectNew);
|
||||
|
||||
assert_eq!(should_replace(&replace, tx_local_low_gas.clone(), tx_local_high_gas.clone()), InsertNew);
|
||||
assert_eq!(should_replace(&replace, tx_local_high_gas.clone(), tx_regular_low_gas.clone()), RejectNew);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_not_replace_ready_transaction_with_future_transaction() {
|
||||
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
|
||||
let client = TestClient::new().with_nonce(1);
|
||||
let replace = ReplaceByScoreAndReadiness::new(scoring, client);
|
||||
|
||||
let tx_ready_low_score = {
|
||||
let tx = Tx {
|
||||
nonce: 1,
|
||||
gas_price: 1,
|
||||
..Default::default()
|
||||
};
|
||||
tx.signed().verified()
|
||||
};
|
||||
let tx_future_high_score = {
|
||||
let tx = Tx {
|
||||
nonce: 3, // future nonce
|
||||
gas_price: 10,
|
||||
..Default::default()
|
||||
};
|
||||
tx.signed().verified()
|
||||
};
|
||||
|
||||
assert_eq!(should_replace(&replace, tx_ready_low_score, tx_future_high_score), RejectNew);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_compute_readiness_with_pooled_transactions_from_the_same_sender_as_the_existing_transaction() {
|
||||
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
|
||||
let client = TestClient::new().with_nonce(1);
|
||||
let replace = ReplaceByScoreAndReadiness::new(scoring, client);
|
||||
|
||||
let old_sender = Random.generate().unwrap();
|
||||
let tx_old_ready_1 = {
|
||||
let tx = Tx {
|
||||
nonce: 1,
|
||||
gas_price: 1,
|
||||
..Default::default()
|
||||
};
|
||||
tx.unsigned().sign(&old_sender.secret(), None).verified()
|
||||
};
|
||||
let tx_old_ready_2 = {
|
||||
let tx = Tx {
|
||||
nonce: 2,
|
||||
gas_price: 1,
|
||||
..Default::default()
|
||||
};
|
||||
tx.unsigned().sign(&old_sender.secret(), None).verified()
|
||||
};
|
||||
let tx_old_ready_3 = {
|
||||
let tx = Tx {
|
||||
nonce: 3,
|
||||
gas_price: 1,
|
||||
..Default::default()
|
||||
};
|
||||
tx.unsigned().sign(&old_sender.secret(), None).verified()
|
||||
};
|
||||
|
||||
let new_tx = {
|
||||
let tx = Tx {
|
||||
nonce: 3, // future nonce
|
||||
gas_price: 10,
|
||||
..Default::default()
|
||||
};
|
||||
tx.signed().verified()
|
||||
};
|
||||
|
||||
let old_tx = txpool::Transaction { insertion_id: 0, transaction: Arc::new(tx_old_ready_3) };
|
||||
let pooled_txs = [
|
||||
txpool::Transaction { insertion_id: 0, transaction: Arc::new(tx_old_ready_1) },
|
||||
txpool::Transaction { insertion_id: 0, transaction: Arc::new(tx_old_ready_2) },
|
||||
];
|
||||
|
||||
let new_tx = txpool::Transaction { insertion_id: 0, transaction: Arc::new(new_tx) };
|
||||
|
||||
let old = ReplaceTransaction::new(&old_tx, Some(&pooled_txs));
|
||||
let new = ReplaceTransaction::new(&new_tx, Default::default());
|
||||
|
||||
assert_eq!(replace.should_replace(&old, &new), RejectNew);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_compute_readiness_with_pooled_transactions_from_the_same_sender_as_the_new_transaction() {
|
||||
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
|
||||
let client = TestClient::new().with_nonce(1);
|
||||
let replace = ReplaceByScoreAndReadiness::new(scoring, client);
|
||||
|
||||
// current transaction is ready but has a lower gas price than the new one
|
||||
let old_tx = {
|
||||
let tx = Tx {
|
||||
nonce: 1,
|
||||
gas_price: 1,
|
||||
..Default::default()
|
||||
};
|
||||
tx.signed().verified()
|
||||
};
|
||||
|
||||
let new_sender = Random.generate().unwrap();
|
||||
let tx_new_ready_1 = {
|
||||
let tx = Tx {
|
||||
nonce: 1,
|
||||
gas_price: 1,
|
||||
..Default::default()
|
||||
};
|
||||
tx.unsigned().sign(&new_sender.secret(), None).verified()
|
||||
};
|
||||
let tx_new_ready_2 = {
|
||||
let tx = Tx {
|
||||
nonce: 2,
|
||||
gas_price: 1,
|
||||
..Default::default()
|
||||
};
|
||||
tx.unsigned().sign(&new_sender.secret(), None).verified()
|
||||
};
|
||||
let tx_new_ready_3 = {
|
||||
let tx = Tx {
|
||||
nonce: 3,
|
||||
gas_price: 10, // hi
|
||||
..Default::default()
|
||||
};
|
||||
tx.unsigned().sign(&new_sender.secret(), None).verified()
|
||||
};
|
||||
|
||||
let old_tx = txpool::Transaction { insertion_id: 0, transaction: Arc::new(old_tx) };
|
||||
|
||||
let new_tx = txpool::Transaction { insertion_id: 0, transaction: Arc::new(tx_new_ready_3) };
|
||||
let pooled_txs = [
|
||||
txpool::Transaction { insertion_id: 0, transaction: Arc::new(tx_new_ready_1) },
|
||||
txpool::Transaction { insertion_id: 0, transaction: Arc::new(tx_new_ready_2) },
|
||||
];
|
||||
|
||||
let old = ReplaceTransaction::new(&old_tx, None);
|
||||
let new = ReplaceTransaction::new(&new_tx, Some(&pooled_txs));
|
||||
|
||||
assert_eq!(replace.should_replace(&old, &new), ReplaceOld);
|
||||
}
|
||||
}
|
||||
@@ -122,29 +122,6 @@ impl<P> txpool::Scoring<P> for NonceAndGasPrice where P: ScoredTransaction + txp
|
||||
}
|
||||
}
|
||||
|
||||
fn should_replace(&self, old: &P, new: &P) -> scoring::Choice {
|
||||
let both_local = old.priority().is_local() && new.priority().is_local();
|
||||
if old.sender() == new.sender() {
|
||||
// prefer earliest transaction
|
||||
match new.nonce().cmp(&old.nonce()) {
|
||||
cmp::Ordering::Equal => self.choose(old, new),
|
||||
_ if both_local => scoring::Choice::InsertNew,
|
||||
cmp::Ordering::Less => scoring::Choice::ReplaceOld,
|
||||
cmp::Ordering::Greater => scoring::Choice::RejectNew,
|
||||
}
|
||||
} else if both_local {
|
||||
scoring::Choice::InsertNew
|
||||
} else {
|
||||
let old_score = (old.priority(), old.gas_price());
|
||||
let new_score = (new.priority(), new.gas_price());
|
||||
if new_score > old_score {
|
||||
scoring::Choice::ReplaceOld
|
||||
} else {
|
||||
scoring::Choice::RejectNew
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn should_ignore_sender_limit(&self, new: &P) -> bool {
|
||||
new.priority().is_local()
|
||||
}
|
||||
@@ -155,156 +132,8 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
use std::sync::Arc;
|
||||
use ethkey::{Random, Generator, KeyPair};
|
||||
use pool::tests::tx::{Tx, TxExt};
|
||||
use txpool::Scoring;
|
||||
use txpool::scoring::Choice::*;
|
||||
|
||||
fn local_tx_verified(tx: Tx, keypair: &KeyPair) -> VerifiedTransaction {
|
||||
let mut verified_tx = tx.unsigned().sign(keypair.secret(), None).verified();
|
||||
verified_tx.priority = ::pool::Priority::Local;
|
||||
verified_tx
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_always_accept_local_transactions_unless_same_sender_and_nonce() {
|
||||
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
|
||||
|
||||
// same sender txs
|
||||
let keypair = Random.generate().unwrap();
|
||||
|
||||
let same_sender_tx1 = local_tx_verified(Tx {
|
||||
nonce: 1,
|
||||
gas_price: 1,
|
||||
..Default::default()
|
||||
}, &keypair);
|
||||
|
||||
let same_sender_tx2 = local_tx_verified(Tx {
|
||||
nonce: 2,
|
||||
gas_price: 100,
|
||||
..Default::default()
|
||||
}, &keypair);
|
||||
|
||||
let same_sender_tx3 = local_tx_verified(Tx {
|
||||
nonce: 2,
|
||||
gas_price: 200,
|
||||
..Default::default()
|
||||
}, &keypair);
|
||||
|
||||
// different sender txs
|
||||
let different_sender_tx1 = local_tx_verified(Tx {
|
||||
nonce: 2,
|
||||
gas_price: 1,
|
||||
..Default::default()
|
||||
}, &Random.generate().unwrap());
|
||||
|
||||
let different_sender_tx2 = local_tx_verified(Tx {
|
||||
nonce: 1,
|
||||
gas_price: 10,
|
||||
..Default::default()
|
||||
}, &Random.generate().unwrap());
|
||||
|
||||
assert_eq!(scoring.should_replace(&same_sender_tx1, &same_sender_tx2), InsertNew);
|
||||
assert_eq!(scoring.should_replace(&same_sender_tx2, &same_sender_tx1), InsertNew);
|
||||
|
||||
assert_eq!(scoring.should_replace(&different_sender_tx1, &different_sender_tx2), InsertNew);
|
||||
assert_eq!(scoring.should_replace(&different_sender_tx2, &different_sender_tx1), InsertNew);
|
||||
|
||||
// txs with same sender and nonce
|
||||
assert_eq!(scoring.should_replace(&same_sender_tx2, &same_sender_tx3), ReplaceOld);
|
||||
assert_eq!(scoring.should_replace(&same_sender_tx3, &same_sender_tx2), RejectNew);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_replace_same_sender_by_nonce() {
|
||||
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
|
||||
|
||||
let tx1 = Tx {
|
||||
nonce: 1,
|
||||
gas_price: 1,
|
||||
..Default::default()
|
||||
};
|
||||
let tx2 = Tx {
|
||||
nonce: 2,
|
||||
gas_price: 100,
|
||||
..Default::default()
|
||||
};
|
||||
let tx3 = Tx {
|
||||
nonce: 2,
|
||||
gas_price: 110,
|
||||
..Default::default()
|
||||
};
|
||||
let tx4 = Tx {
|
||||
nonce: 2,
|
||||
gas_price: 130,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let keypair = Random.generate().unwrap();
|
||||
let txs = vec![tx1, tx2, tx3, tx4].into_iter().map(|tx| {
|
||||
tx.unsigned().sign(keypair.secret(), None).verified()
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(scoring.should_replace(&txs[0], &txs[1]), RejectNew);
|
||||
assert_eq!(scoring.should_replace(&txs[1], &txs[0]), ReplaceOld);
|
||||
|
||||
assert_eq!(scoring.should_replace(&txs[1], &txs[2]), RejectNew);
|
||||
assert_eq!(scoring.should_replace(&txs[2], &txs[1]), RejectNew);
|
||||
|
||||
assert_eq!(scoring.should_replace(&txs[1], &txs[3]), ReplaceOld);
|
||||
assert_eq!(scoring.should_replace(&txs[3], &txs[1]), RejectNew);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_replace_different_sender_by_priority_and_gas_price() {
|
||||
// given
|
||||
let scoring = NonceAndGasPrice(PrioritizationStrategy::GasPriceOnly);
|
||||
let tx_regular_low_gas = {
|
||||
let tx = Tx {
|
||||
nonce: 1,
|
||||
gas_price: 1,
|
||||
..Default::default()
|
||||
};
|
||||
tx.signed().verified()
|
||||
};
|
||||
let tx_regular_high_gas = {
|
||||
let tx = Tx {
|
||||
nonce: 2,
|
||||
gas_price: 10,
|
||||
..Default::default()
|
||||
};
|
||||
tx.signed().verified()
|
||||
};
|
||||
let tx_local_low_gas = {
|
||||
let tx = Tx {
|
||||
nonce: 2,
|
||||
gas_price: 1,
|
||||
..Default::default()
|
||||
};
|
||||
let mut verified_tx = tx.signed().verified();
|
||||
verified_tx.priority = ::pool::Priority::Local;
|
||||
verified_tx
|
||||
};
|
||||
let tx_local_high_gas = {
|
||||
let tx = Tx {
|
||||
nonce: 1,
|
||||
gas_price: 10,
|
||||
..Default::default()
|
||||
};
|
||||
let mut verified_tx = tx.signed().verified();
|
||||
verified_tx.priority = ::pool::Priority::Local;
|
||||
verified_tx
|
||||
};
|
||||
|
||||
assert_eq!(scoring.should_replace(&tx_regular_low_gas, &tx_regular_high_gas), ReplaceOld);
|
||||
assert_eq!(scoring.should_replace(&tx_regular_high_gas, &tx_regular_low_gas), RejectNew);
|
||||
|
||||
assert_eq!(scoring.should_replace(&tx_regular_high_gas, &tx_local_low_gas), ReplaceOld);
|
||||
assert_eq!(scoring.should_replace(&tx_local_low_gas, &tx_regular_high_gas), RejectNew);
|
||||
|
||||
assert_eq!(scoring.should_replace(&tx_local_low_gas, &tx_local_high_gas), InsertNew);
|
||||
assert_eq!(scoring.should_replace(&tx_local_high_gas, &tx_regular_low_gas), RejectNew);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_calculate_score_correctly() {
|
||||
|
||||
@@ -16,11 +16,15 @@
|
||||
|
||||
//! A service transactions contract checker.
|
||||
|
||||
use call_contract::{CallContract, RegistryInfo};
|
||||
use std::collections::HashMap;
|
||||
use std::mem;
|
||||
use std::sync::Arc;
|
||||
use call_contract::{RegistryInfo, CallContract};
|
||||
use types::ids::BlockId;
|
||||
use types::transaction::SignedTransaction;
|
||||
use ethabi::FunctionOutputDecoder;
|
||||
use ethereum_types::Address;
|
||||
use parking_lot::RwLock;
|
||||
|
||||
use_contract!(service_transaction, "res/contracts/service_transaction.json");
|
||||
|
||||
@@ -28,9 +32,12 @@ const SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME: &'static str = "service_transa
|
||||
|
||||
/// Service transactions checker.
|
||||
#[derive(Default, Clone)]
|
||||
pub struct ServiceTransactionChecker;
|
||||
pub struct ServiceTransactionChecker {
|
||||
certified_addresses_cache: Arc<RwLock<HashMap<Address, bool>>>
|
||||
}
|
||||
|
||||
impl ServiceTransactionChecker {
|
||||
|
||||
/// Checks if given address in tx is whitelisted to send service transactions.
|
||||
pub fn check<C: CallContract + RegistryInfo>(&self, client: &C, tx: &SignedTransaction) -> Result<bool, String> {
|
||||
let sender = tx.sender();
|
||||
@@ -44,9 +51,42 @@ impl ServiceTransactionChecker {
|
||||
|
||||
/// Checks if given address is whitelisted to send service transactions.
|
||||
pub fn check_address<C: CallContract + RegistryInfo>(&self, client: &C, sender: Address) -> Result<bool, String> {
|
||||
trace!(target: "txqueue", "Checking service transaction checker contract from {}", sender);
|
||||
if let Some(allowed) = self.certified_addresses_cache.try_read().as_ref().and_then(|c| c.get(&sender)) {
|
||||
return Ok(*allowed);
|
||||
}
|
||||
let contract_address = client.registry_address(SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME.to_owned(), BlockId::Latest)
|
||||
.ok_or_else(|| "contract is not configured")?;
|
||||
trace!(target: "txqueue", "Checking service transaction checker contract from {}", sender);
|
||||
self.call_contract(client, contract_address, sender).and_then(|allowed| {
|
||||
if let Some(mut cache) = self.certified_addresses_cache.try_write() {
|
||||
cache.insert(sender, allowed);
|
||||
};
|
||||
Ok(allowed)
|
||||
})
|
||||
}
|
||||
|
||||
/// Refresh certified addresses cache
|
||||
pub fn refresh_cache<C: CallContract + RegistryInfo>(&self, client: &C) -> Result<bool, String> {
|
||||
trace!(target: "txqueue", "Refreshing certified addresses cache");
|
||||
// replace the cache with an empty list,
|
||||
// since it's not recent it won't be used anyway.
|
||||
let cache = mem::replace(&mut *self.certified_addresses_cache.write(), HashMap::default());
|
||||
|
||||
if let Some(contract_address) = client.registry_address(SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME.to_owned(), BlockId::Latest) {
|
||||
let addresses: Vec<_> = cache.keys().collect();
|
||||
let mut cache: HashMap<Address, bool> = HashMap::default();
|
||||
for address in addresses {
|
||||
let allowed = self.call_contract(client, contract_address, *address)?;
|
||||
cache.insert(*address, allowed);
|
||||
}
|
||||
mem::replace(&mut *self.certified_addresses_cache.write(), cache);
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
fn call_contract<C: CallContract + RegistryInfo>(&self, client: &C, contract_address: Address, sender: Address) -> Result<bool, String> {
|
||||
let (data, decoder) = service_transaction::functions::certified::call(sender);
|
||||
let value = client.call_contract(BlockId::Latest, contract_address, data)?;
|
||||
decoder.decode(&value).map_err(|e| e.to_string())
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user