Backports to 2.0.0-beta (#9094)

* parity-version: betalize 2.0

* Multiple improvements to discovery ping handling (#8771)

* discovery: Only add nodes to routing table after receiving pong.

Previously the discovery algorithm would add nodes to the routing table
before confirming that the endpoint is participating in the protocol. This
now tracks in-flight pings and adds to the routing table only after receiving
a response.

* discovery: Refactor packet creation into its own function.

This function is useful inside unit tests.

* discovery: Additional testing for new add_node behavior.

* discovery: Track expiration of pings to non-yet-in-bucket nodes.

Now that we may ping nodes before adding to a k-bucket, the timeout tracking
must be separate from BucketEntry.

* discovery: Verify echo hash on pong packets.

Stores packet hash with in-flight requests and matches with pong response.

* discovery: Track timeouts on FIND_NODE requests.

* discovery: Retry failed pings with exponential backoff.

UDP packets may get dropped, so instead of immediately booting nodes that fail
to respond to a ping, retry 4 times with exponential backoff.

* !fixup Use slice instead of Vec for request_backoff.

* Add separate database directory for light client (#8927) (#9064)

* Add seperate default DB path for light client (#8927)

* Improve readability

* Revert "Replace `std::env::home_dir` with `dirs::home_dir` (#9077)" (#9097)

* Revert "Replace `std::env::home_dir` with `dirs::home_dir` (#9077)"

This reverts commit 7e779327eb.

* Restore some of the changes

* Update parity-common

* Offload cull to IoWorker. (#9099)

* Fix work-notify. (#9104)

* Update hidapi, fixes #7542 (#9108)

* docker: add cmake dependency (#9111)

* Update light client hardcoded headers (#9098)

* Insert Kovan hardcoded headers until #7690241

* Insert Kovan hardcoded headers until block 7690241

* Insert Ropsten hardcoded headers until #3612673

* Insert Mainnet hardcoded headers until block 5941249

* Make sure to produce full blocks. (#9115)

* Insert ETC (classic) hardcoded headers until block #6170625 (#9121)

* fix verification in ethcore-sync collect_blocks (#9135)

* Completely remove all dapps struct from rpc (#9107)

* Completely remove all dapps struct from rpc

* Remove unused pub use

* `evm bench` fix broken dependencies (#9134)

* `evm bench` use valid dependencies

Benchmarks of the `evm` used stale versions of a couple a crates that
this commit fixes!

* fix warnings

* Update snapcraft.yaml (#9132)
This commit is contained in:
Afri Schoedon 2018-07-17 13:47:14 +02:00 committed by GitHub
parent 484ecfaf47
commit 6eae372524
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 3947 additions and 461 deletions

44
Cargo.lock generated
View File

@ -351,20 +351,10 @@ name = "dir"
version = "0.1.1"
dependencies = [
"app_dirs 1.2.1 (git+https://github.com/paritytech/app-dirs-rs)",
"dirs 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"journaldb 0.2.0",
]
[[package]]
name = "dirs"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "docopt"
version = "0.8.3"
@ -1173,7 +1163,7 @@ dependencies = [
[[package]]
name = "hashdb"
version = "0.2.0"
source = "git+https://github.com/paritytech/parity-common#a72c34f82ff7ccc0f49827bb7f8c5d1fbff794bb"
source = "git+https://github.com/paritytech/parity-common#5f05acd90cf173f2e1ce477665be2a40502fef42"
dependencies = [
"elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1203,7 +1193,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "hidapi"
version = "0.3.1"
source = "git+https://github.com/paritytech/hidapi-rs#70ec4bd1b755ec5dd32ad2be0c8345864147c8bc"
source = "git+https://github.com/paritytech/hidapi-rs#d4d323767d6f27cf5a3d73fbae0b0f2134d579bf"
dependencies = [
"cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1437,7 +1427,7 @@ dependencies = [
[[package]]
name = "keccak-hash"
version = "0.1.2"
source = "git+https://github.com/paritytech/parity-common#a72c34f82ff7ccc0f49827bb7f8c5d1fbff794bb"
source = "git+https://github.com/paritytech/parity-common#5f05acd90cf173f2e1ce477665be2a40502fef42"
dependencies = [
"ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1465,7 +1455,7 @@ dependencies = [
[[package]]
name = "kvdb"
version = "0.1.0"
source = "git+https://github.com/paritytech/parity-common#a72c34f82ff7ccc0f49827bb7f8c5d1fbff794bb"
source = "git+https://github.com/paritytech/parity-common#5f05acd90cf173f2e1ce477665be2a40502fef42"
dependencies = [
"elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)",
@ -1474,7 +1464,7 @@ dependencies = [
[[package]]
name = "kvdb-memorydb"
version = "0.1.0"
source = "git+https://github.com/paritytech/parity-common#a72c34f82ff7ccc0f49827bb7f8c5d1fbff794bb"
source = "git+https://github.com/paritytech/parity-common#5f05acd90cf173f2e1ce477665be2a40502fef42"
dependencies = [
"kvdb 0.1.0 (git+https://github.com/paritytech/parity-common)",
"parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1483,7 +1473,7 @@ dependencies = [
[[package]]
name = "kvdb-rocksdb"
version = "0.1.0"
source = "git+https://github.com/paritytech/parity-common#a72c34f82ff7ccc0f49827bb7f8c5d1fbff794bb"
source = "git+https://github.com/paritytech/parity-common#5f05acd90cf173f2e1ce477665be2a40502fef42"
dependencies = [
"elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1654,7 +1644,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memorydb"
version = "0.2.0"
source = "git+https://github.com/paritytech/parity-common#a72c34f82ff7ccc0f49827bb7f8c5d1fbff794bb"
source = "git+https://github.com/paritytech/parity-common#5f05acd90cf173f2e1ce477665be2a40502fef42"
dependencies = [
"elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hashdb 0.2.0 (git+https://github.com/paritytech/parity-common)",
@ -1951,7 +1941,7 @@ dependencies = [
[[package]]
name = "parity-bytes"
version = "0.1.0"
source = "git+https://github.com/paritytech/parity-common#a72c34f82ff7ccc0f49827bb7f8c5d1fbff794bb"
source = "git+https://github.com/paritytech/parity-common#5f05acd90cf173f2e1ce477665be2a40502fef42"
[[package]]
name = "parity-clib"
@ -1963,7 +1953,7 @@ dependencies = [
[[package]]
name = "parity-crypto"
version = "0.1.0"
source = "git+https://github.com/paritytech/parity-common#a72c34f82ff7ccc0f49827bb7f8c5d1fbff794bb"
source = "git+https://github.com/paritytech/parity-common#5f05acd90cf173f2e1ce477665be2a40502fef42"
dependencies = [
"ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2328,15 +2318,12 @@ dependencies = [
[[package]]
name = "path"
version = "0.1.1"
source = "git+https://github.com/paritytech/parity-common#a72c34f82ff7ccc0f49827bb7f8c5d1fbff794bb"
dependencies = [
"dirs 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
source = "git+https://github.com/paritytech/parity-common#5f05acd90cf173f2e1ce477665be2a40502fef42"
[[package]]
name = "patricia-trie"
version = "0.2.1"
source = "git+https://github.com/paritytech/parity-common#a72c34f82ff7ccc0f49827bb7f8c5d1fbff794bb"
source = "git+https://github.com/paritytech/parity-common#5f05acd90cf173f2e1ce477665be2a40502fef42"
dependencies = [
"elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hashdb 0.2.0 (git+https://github.com/paritytech/parity-common)",
@ -2411,7 +2398,7 @@ dependencies = [
[[package]]
name = "plain_hasher"
version = "0.1.0"
source = "git+https://github.com/paritytech/parity-common#a72c34f82ff7ccc0f49827bb7f8c5d1fbff794bb"
source = "git+https://github.com/paritytech/parity-common#5f05acd90cf173f2e1ce477665be2a40502fef42"
dependencies = [
"crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2647,7 +2634,7 @@ dependencies = [
[[package]]
name = "rlp"
version = "0.2.1"
source = "git+https://github.com/paritytech/parity-common#a72c34f82ff7ccc0f49827bb7f8c5d1fbff794bb"
source = "git+https://github.com/paritytech/parity-common#5f05acd90cf173f2e1ce477665be2a40502fef42"
dependencies = [
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3324,7 +3311,7 @@ dependencies = [
[[package]]
name = "trie-standardmap"
version = "0.1.0"
source = "git+https://github.com/paritytech/parity-common#a72c34f82ff7ccc0f49827bb7f8c5d1fbff794bb"
source = "git+https://github.com/paritytech/parity-common#5f05acd90cf173f2e1ce477665be2a40502fef42"
dependencies = [
"ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)",
@ -3335,7 +3322,7 @@ dependencies = [
[[package]]
name = "triehash"
version = "0.2.0"
source = "git+https://github.com/paritytech/parity-common#a72c34f82ff7ccc0f49827bb7f8c5d1fbff794bb"
source = "git+https://github.com/paritytech/parity-common#5f05acd90cf173f2e1ce477665be2a40502fef42"
dependencies = [
"elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3668,7 +3655,6 @@ dependencies = [
"checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9"
"checksum daemonize 0.2.3 (git+https://github.com/paritytech/daemonize)" = "<none>"
"checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8"
"checksum dirs 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "37a76dd8b997af7107d0bb69d43903cf37153a18266f8b3fdb9911f28efb5444"
"checksum docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d8acd393692c503b168471874953a2531df0e9ab77d0b6bbc582395743300a4a"
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
"checksum edit-distance 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6a34f5204fbc13582de418611cf3a7dcdd07c6d312a5b631597ba72c06b9d9c9"

View File

@ -32,7 +32,7 @@ futures-cpupool = "0.1"
fdlimit = "0.1"
ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" }
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" }
ethcore = { path = "ethcore", features = ["work-notify", "price-info", "stratum"] }
ethcore = { path = "ethcore", features = ["parity"] }
parity-bytes = { git = "https://github.com/paritytech/parity-common" }
ethcore-io = { path = "util/io" }
ethcore-light = { path = "ethcore/light" }
@ -88,6 +88,7 @@ winapi = { version = "0.3.4", features = ["winsock2", "winuser", "shellapi"] }
daemonize = { git = "https://github.com/paritytech/daemonize" }
[features]
miner-debug = ["ethcore/miner-debug"]
json-tests = ["ethcore/json-tests"]
test-heavy = ["ethcore/test-heavy"]
evm-debug = ["ethcore/evm-debug"]

View File

@ -5,7 +5,7 @@ WORKDIR /build
# install tools and dependencies
RUN apk add --no-cache gcc musl-dev pkgconfig g++ make curl \
eudev-dev rust cargo git file binutils \
libusb-dev linux-headers perl
libusb-dev linux-headers perl cmake
# show backtraces
ENV RUST_BACKTRACE 1

View File

@ -3,7 +3,7 @@ WORKDIR /build
# install tools and dependencies
RUN yum -y update&& \
yum install -y git make gcc-c++ gcc file binutils
yum install -y git make gcc-c++ gcc file binutils cmake
# install rustup
RUN curl -sSf https://static.rust-lang.org/rustup.sh -o rustup.sh &&\

View File

@ -13,6 +13,7 @@ RUN apt-get update && \
# add-apt-repository
software-properties-common \
make \
cmake \
curl \
wget \
git \

View File

@ -6,7 +6,7 @@ RUN apt-get -y update && \
apt-get install -y --force-yes --no-install-recommends \
curl git make g++ gcc-aarch64-linux-gnu g++-aarch64-linux-gnu \
libc6-arm64-cross libc6-dev-arm64-cross wget file ca-certificates \
binutils-aarch64-linux-gnu \
binutils-aarch64-linux-gnu cmake \
&& \
apt-get clean

View File

@ -6,7 +6,7 @@ RUN apt-get -y update && \
apt-get install -y --force-yes --no-install-recommends \
curl git make g++ gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf \
libc6-dev-armhf-cross wget file ca-certificates \
binutils-arm-linux-gnueabihf \
binutils-arm-linux-gnueabihf cmake \
&& \
apt-get clean

View File

@ -6,6 +6,7 @@ RUN apt-get update && \
apt-get install -y \
g++ \
build-essential \
cmake \
curl \
git \
file \

View File

@ -80,6 +80,17 @@ tempdir = "0.3"
trie-standardmap = { git = "https://github.com/paritytech/parity-common" }
[features]
parity = ["work-notify", "price-info", "stratum"]
# Large optional features that are enabled by default for Parity,
# but might be omitted for other dependent crates.
work-notify = ["ethcore-miner/work-notify"]
price-info = ["ethcore-miner/price-info"]
stratum = ["ethcore-stratum"]
# Disables seal verification for mined blocks.
# This allows you to submit any seal via RPC to test and benchmark
# how fast pending block get's created while running on the mainnet.
miner-debug = []
# Display EVM debug traces.
evm-debug = ["evm/evm-debug"]
# Display EVM debug traces when running tests.
@ -97,6 +108,3 @@ test-heavy = []
benches = []
# Compile test helpers
test-helpers = ["tempdir"]
work-notify = ["ethcore-miner/work-notify"]
price-info = ["ethcore-miner/price-info"]
stratum = ["ethcore-stratum"]

View File

@ -16,17 +16,16 @@
#![feature(test)]
extern crate test;
extern crate ethcore_util as util;
extern crate rand;
extern crate bn;
extern crate parity_crypto;
extern crate ethereum_types;
extern crate ethkey;
extern crate parity_crypto;
extern crate rand;
extern crate rustc_hex;
extern crate ethcore_bigint;
extern crate test;
use self::test::{Bencher};
use rand::{StdRng};
use self::test::Bencher;
use rand::StdRng;
#[bench]
fn bn_128_pairing(b: &mut Bencher) {
@ -62,8 +61,7 @@ fn bn_128_mul(b: &mut Bencher) {
fn sha256(b: &mut Bencher) {
use parity_crypto::digest::sha256;
let mut input: [u8; 256] = [0; 256];
let mut out = [0; 32];
let input = [0_u8; 256];
b.iter(|| {
sha256(&input);
@ -74,7 +72,7 @@ fn sha256(b: &mut Bencher) {
fn ecrecover(b: &mut Bencher) {
use rustc_hex::FromHex;
use ethkey::{Signature, recover as ec_recover};
use ethcore_bigint::hash::H256;
use ethereum_types::H256;
let input = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();
let hash = H256::from_slice(&input[0..32]);
let v = H256::from_slice(&input[32..64]);

File diff suppressed because it is too large Load Diff

View File

@ -173,9 +173,9 @@
"gasLimit": "0x1388",
"stateRoot": "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544"
},
"hardcodedSync": {
"header": "f90207a0cdaf426b80edd4363b336b351cbfec8c38b44847cdbd814aa92e92bc9ec05333a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347949435d50503aee35c8757ae4933f7a0ab56597805a03f28b2b384dbfd29bc0a10343e8a419e61b92782f880046170bf1d11455e94bba0f3712ef3ff24efe1afc7da11ffb2ca495a94fe7958f42e9f1599d66ed72af13ba06d01d03a15f807da601bd2dfde7490bbe91d9bb11c11eda435db9daad6e7b1efb9010000008c0000c000000000440100108040000082000800000000000000040801001004001000000010000000001000043300001000008000800000002000200040000000580c0004108000040c0008000006000000000280800080000800000000402000000a000000a810226200002881004000208006020000000510030000100040010100000086c20000000009000100000190008c80060000008000202080420008056040000000001000400001100010140822800220000c804004002000108000160001400200088082008000000412100010080205011000000800a0000810021005000000000002840000000400000000880000006000000000200002870bfca554dbc6398358b001837a137083473c8e845b27f4fd86436f72746578a0dbf31fd28bd8f69f1103196e1782a9dfb636bcfa726362ab0767235cb8d56e7188264402501145497f",
"totalDifficulty": "4838383800145139949936",
"hardcodedSync": {
"header": "f9020ba0bb120488b73cb04a3c423dfa6760eb631165fa3d6d8e0b1be360d3e2a00add78a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479452e44f279f4203dcf680395379e5f9990a69f13ca02d2cbb3c43370257122898259f1e06da38fd23031f74b40d6bd022b037ecd3daa0107b3a01662ca77aa1c72cde45bd66c062d781310d7a364e5b6442bd791431cea011e451bfe7b89addb96020182e0e7eb448d0a66303924a2835a149247bea4188b90100000000200004820000130000020000322004002000140000801000081208000880800200100000000a080000000800400000000000080240800000020028a100000400410000001088008008400080000100000000200000000220804028000000302000000180200c004644000000000101800000040040020200100020100220200a00000000280002011040000000000080a00000002002048000100001000206000000c000002010000004800030000000000300884008121000208020080000020280000000010104002000004000002084000c08402820000004000001841109008410040410080080004121044080800800000000004858040000c000870c64944ccfd130835aa801837a212d8320dc6b845b452c758a7777772e62772e636f6da02078861f3b30aaea6fad290d86919dd7542433a56edc1af557426cbd2eacd60d88a68a26940894b23f",
"totalDifficulty": "5282739680501645457616",
"CHTs": [
"0x0eb474b7721727204978e92e27d31cddff56471911e424a4c8271c35f9c982cc",
"0xe10e94515fb5ffb7ffa9bf50db4a959b3f50c2ff75e0b8bd5f5e038749e52a11",
@ -3014,7 +3014,70 @@
"0x118b3ae7ad25ab96fe8a63973312c758d4ce9ecd39cc24913c26a65b4b5534de",
"0x19cd088af8dbe2d3e6ca7987d9ee1564ea2256f482840b1d2f0da85060de9a86",
"0x98bc07422cf8b0c4d1428afb759300d9a7637de2518528d34f7d237be7e863be",
"0x0c64526b393066911c7da3f17f9e652cfa38112ae324e3c84416e811d3fe7cad"
"0x0c64526b393066911c7da3f17f9e652cfa38112ae324e3c84416e811d3fe7cad",
"0xa30cbfaf518996ba776b426a7068faad4ee49775db45565ebd327f9c679a45b4",
"0xd3e1a807f5940ee1a321b20b7931bef90515132ea9959df94e55529e05802cab",
"0x338aef579d9ec8acc1a0411c1674bcf213d03aa7d4bbc56707e081829ce30004",
"0x68c7a603089a220273f019001a39bfa9194590a6fa6d8ba960ddf4888b105a6b",
"0xd6a9d2c354e1dd77322800d24774eb03b589dd94bcdb3cc2b70437ed70411e6a",
"0x39c017c42ad571564792bf5741b3ae786ff0c24ebcb5ee46882ce0545b8a2262",
"0xf5caea6b23f4085c9f94c880d89b1c23eb69c03dc098b426143ae4b28969a2d8",
"0x959eebc05ff0dfae8c7e6699f069b38b5f2e5bc8c155bc35fc7f578d2d112993",
"0x199e90557d4d9e13c3e7a4b5b4ef6fe52cd2c724c36eaa44b7fa151efebbbeee",
"0x0bfe35d253227696e76f92ff13e4c545c57fca51186a16f687e76d2e6707d34f",
"0xadf8b7678f98b0e5009130d9d5d77add6e460b67b0529abc5315c44dadea0cb4",
"0x86582f3a98b218939aefd7eea438ee278d1faaf41920e8c72922c46fd56f1c32",
"0x001b728a4737fdd53cde20341fa0adec9aa8ab7c7c1db244fbd509a6c4f3f364",
"0x9207900bfdd6c87e2ba8498c0372706799604a207930eeb331580459d17f89cb",
"0xd2192fcf74cad70e6f7986a0b088de8658a14638a4c03d7ae616a88ceea00ba2",
"0xbf6f6b91742eebe70204eb7a70196ef636fc2db4d4c4f89cd5826fbf990a945d",
"0x5c1210951949402fe3b012577f1af0d3e285a0b39c3fe19c84f7930e003c06de",
"0xa16d57f777f94f032f7f2f75b2e25ebd11559effee98b39a5a1e7cc804cfbf06",
"0x1b9561fb8035ec6955454d6710f053d7ad3d8e0753aaac568ac3bc98f874465e",
"0x1a622da786425e0b65b9083a451a419c75e16908fa04d89ddc2c11d94ffe65a0",
"0xbfcb9b1d847eb40b6808e45bf3d2fb8f6588d6f103167be65f246d0733afd1f7",
"0x2317640589ab9d52e7f5e8dda95ff3b1beceacc5832341e9053b71209bfad07f",
"0xa10611b829dbb533e565ad01632b26b1fd642a4393e7fdd9b8f235f11bb606c8",
"0xe4ea4173982f342e396356b0bb0eb47e6748461ecce0f34dbe8fc084cf6a9fbc",
"0xd58399c0d0ae878338d2915eaf2d65f2d1e29eb8d551d254e68bce7a8235adcb",
"0xc0c8b73ffc675a207f73903c49d81131e6831e4c8e071b988ed9f2a5d2277024",
"0xe1ca77bafa66bb055c671978b3d1bd5df32f8e269330507f071afd627012b6af",
"0x67a1093cbddf41264009d1dbbc33fbc25a337339be0727e70c512b585897749c",
"0x0fd615782db5cf4c0a3686721cbc6245696c1bc9b403a9eaffae00968d2c8ece",
"0xc3c2dcaee8954ca86d9b3e4e98c4bb4f6b6bc183f9eb062016c5a25b2280717b",
"0x70265915f5ed94d589afafa3d0d0eab6310195cc690aa82bd65e4a488b398c58",
"0xde3fead8ce29c04a86dcb081da2cabda5366d28de5ebfe2f8064780413f71edf",
"0x0ae43394fcf6ebdabdcc1ede314fe779eb61a12eab807a9d3437d9167e2247e3",
"0x3241127e2c7fbb3db9fe0c602b0c94e22c684b7910ffcf09c1c443e567f95e4d",
"0xcb94ba286eeaa1129b490bb5891e603fd35e85c97c2132c1216d1774f9017f35",
"0xbf396cd23c29ef21fb535880ef621457fb71981f856f2a09c494cd005d38f981",
"0x3df0c90ed7aba260e820ca1d28ce1778149e163524e306309aa346bbadedcf2b",
"0x66a2724f7481aa3ab83a8f1bae2caef8a7bc607c7ffd5bbb1cf3766741db804f",
"0x7a0c3492f4022322e10d81bc10a5db9aceec81d1ab70cdffd31418b79d750fd2",
"0x96a826cb667924ed75ec708bf07cf4c7c05f84a0132e154b71eaf6e193590e87",
"0xcc7030fe617c318a31984d04e3d7f2ff2196894bc429f3f64bfd69b969dc9b56",
"0x3fa94aae223f5aeb593246f1a93d6d694b48946c09d879e791f1188a9dedc4c0",
"0xd49e51fc324fe58159575c0c24171f4eb1aaf58ed8e1311c3849538c8cec3ce1",
"0xc474123906eae5cd48a10e0d93fcbbd653f0c6d25275f827d4fac51e696c3d91",
"0xacd7b790a19026fa3f3b0a354878d4fcd79dc600f7ba5cedd2eefffe1ceda76c",
"0x41b311a188cd7ce1444d258dc379994b81a895226276c7bfe5e6cb29a5f92142",
"0xda0ae01db7f73f07fce46b94c24d6e400598378a6baf01123dd710c5425fb8c9",
"0xe62e08175a02b575e28b9e029a838c365e3ce4278f60c2d3b5d529768a4b47c4",
"0x99b804c8d0feda7f9df961527d634fb8b2d477a362e1d8158856885a13425fa9",
"0xe73597be8ef7d78f862c7a94a8ccff17f559816eba2f830821c6f6436898f9fb",
"0x36de9ee4c80853c865b16904cd8f6c0e9a99ff9e7bf05100bfbc76789cedd4d1",
"0xf480b762872373102393461ff3a21323a1df799c315fd167780a45d7bfaae84e",
"0x303b66babd21e72449cad413e04bdb0bc3ebcbb84a79dd30ed7c972c5341b82b",
"0xbf111684fbe44a973594f31cdee2c94e807bff9cf7584c22dcd609d8234f6e62",
"0x79b26cc3bbf49b6f25afbff7e97e4e45f2dcb359095fdbeb7fb7addee692afc3",
"0x2839d620cc140ba838ecba6e7e52db8cf7b5cd4cf4857f72f3bfbc9b1cf0fbd9",
"0x93074136f4eec367adcf27955d38efc0dc6da514693bfc97935c7871793e35ea",
"0x21f5af18a4cf0096b6e6a3d4c98f4043cfee5c4ee085ce106f86b713160144b8",
"0x90d16b403e2deca6cd5c80e52eba0b84b2875e1dfd75fffb1a2f82bc91eb6942",
"0x8a5cb6854c19a865f51e3ee9eaf8e843a97b272f6467634ba40e547a435ef624",
"0x9afe42a0dffca8ec063c83908fd6237d6130c9dfeab57078bdd02b6ac6d0ea07",
"0xa05cc6108b475d3e68e280e98f514cfb6df4f004e1b7708fcfd4528d346bea6b",
"0x71f10879b875caefab46669e8525b9c0487bbe3247e43a6cdb1dedbfb4d4ba33"
]
},
"nodes": [

View File

@ -57,7 +57,7 @@
},
"hardcodedSync": {
"header": "f9023ea070413bfe3ceb9160c7dee87bf060a0cc5e324f7c539cfce4e78802ff805063b6a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479400e4a10650e5a6d6001c38ff8e64f97016a1645ca0f8ac12c30b4fd0d27a1a50c090659014574b554ba6e9cdb76f57efbcfbd390a9a0b474ac6cc4673c17c5f511a8b43cc44dbb01bb028735830163667d7a3a2582b9a0bcd44b7c04fa24760df7d733ca8ecd99e8da89de0716e6017fffa434bfd7519ab901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090fffffffffffffffffffffffffffffffd83755801837a11f88301d8de845b27471c96d583010b038650617269747986312e32362e31826c698416c9d1c7b8418bc805f23fb01fdd498b37df5519f49691d65160fe6a6794b8106e2ecc4782407f0dae3a512546b7d93e89bbb2a761c750553deeea1f9401231f56ae0ccb059201",
"totalDifficulty": "2566410291882451733317698215999610733750372193",
"totalDifficulty": "2654916374389120143910668097894183918476475680",
"CHTs": [
"0xdb9557458495268ddd69409fc1f66631ed5ff9bf6c479be6eabe5d83a460acac",
"0xd413800c22172be6e0b7a36348c90098955991f119ddad32c5b928e8db4deb02",
@ -3813,7 +3813,134 @@
"0x5d71aff2a12d4f1d05c7f760d07b417a39eb0eaa72a01333befc6a2eb6b7d72a",
"0x8dd7de9195d2852aeb6812638ba22e73ff5ca0a8ad921c6e924cae1dd5952255",
"0x8f1828b4cdc6c38c112b1ffee7790953112dd2225ec82581a5095e5ae4d71cae",
"0xfeac88ae6c8529e87a55a259f475b7d162d01e8fa5f36c90d4665dd6105b1743"
"0xfeac88ae6c8529e87a55a259f475b7d162d01e8fa5f36c90d4665dd6105b1743",
"0x2e37011bd97c6e8a24e130fdc2c60c39b14ab3eb426a4f654bf3158a19aca88b",
"0xdb59b565de21902c50e2e204374ae1ce487656eb74145c103a86707b45a63eaf",
"0xf75c26a7214acf2d050ff5c7cc8b76e1a90540410b5c8b2bc9edbfe8fb2268e6",
"0x6ca7554f2abfd22951bec80f9d280abb6f060dde4a9a829ff7a0457d67a99edd",
"0x0324bceb8b61fa7092396764d7e1933697806c6d785446e3bbab3fc3be0ab259",
"0xeb4880f177e3e673f8ee04be1451a38bd8a2c0bac681d82a19327ae2d9769d32",
"0xec6a868cd9fba9e4f5b0d4276f44aee71056fbb7f425f717d0ce9d1fa5442ded",
"0xdc12b36d165eae197487ec930e35489545d2867b6fb9f8604d279337b6a8f949",
"0xcf1241b1c9b054df34638e99447bb0359aa01ad13c38650b872f2d727e6f68f6",
"0x713765e9b76c73c2de58c480600a7125972246fdcce2324993cd6bbe49cce67f",
"0x81e096e97dd8bf1d206d0ed41c9feaad24d344323ff74707112ee8fac218994e",
"0x8943c2246d5ae3e8db5fc012e9613642c6b713e5f2a89d00f09fa73246f88d5f",
"0x5b2d0bcbd893fab4e58d4ef698d1e8d3001799b61e758b7711f319e2b8eaa645",
"0xf3e4da2cf4579f52b7e4d632d93b79714487ef179a8f5d5c46af9154efad20fd",
"0xa2348ea2cd7a5a32779e9d292a9428fa475fae790f08e42f7699ef5eb2489188",
"0x62dd923966e02db7d0d27cfdd4aeac081f9827288c8b54d9f19035331a109f53",
"0xaa1aafa8f9d9d3e0668eff761fbfc2657d1e1906c077d93200ec000643c6c272",
"0xbf40cb21561989004434d6d908451d5b63045c89c2ac9b1eb617ec0054dc18be",
"0xdae53edbb07fe84623451da0e25da631ad3465e5bc12ef8fd8323c8a72f57130",
"0x685115b38f307f984c7c90e85d167d62b0ec2c924a0bca5f23b1cac12a8f72fa",
"0x2ad7e8f86c872504d7c2c48b0db141955d770acc84222fd725ffbd2dc4095b1d",
"0x9268b3b175aa6025b959b8fcdb416c39dd339e6f1fde3c427bd1bada36e4384c",
"0x502ee814cecc8454abb95591b0d07ed5170db94af7fda8878b9b4287fd68c9f8",
"0x6b19baf6b7eae36c0b1d2754645ff282fc2905802ca6394ac00bc22eb1582eb9",
"0xecad17ae39f897ab38850cac40480b4fafcafd6624f8fdfcaa69849f3fa101ec",
"0xb0804719b391b4b5f554a49f99df3a9d1c3a9884cefc268dcb27e3821aebe385",
"0x3018401c9a31f97881852c1bd65a964bfd3011659725c849a8de4b5ad8f26490",
"0x48a6b687e62a42dc44ecb56f4187e293d6f87d328b1edf409c8f2fa6568dfddc",
"0x8e3bc1ec926a68e22ed525485186a4d9160a54bd3e80107bb77c09911564effa",
"0xd7a7cce632e1746120476a3271ea09689380eb833d5538310fa0029f9174e0de",
"0x7bae074c51f3b547568d18e85b73fcb9b5f8040ed5f96f3523f53197150517a4",
"0x9ba39f376b9444dab04e0a52e4728ec842a0aa4880d9aa9819de3f0694f46e60",
"0x40a2b84bd3d05d28d51a39deae5f23b4f7370c70ac70d1cc81224eac4939d69f",
"0x2b9f57c8c43284ba929df8f896a966afbdd341f145b6b2b2fa98382950ad915d",
"0xcaf3d2a336cf17c9b2d7116a14e654bcece012b07bc020ac30feb71d7f6cead1",
"0xd3b68cf2337ca26a9c4bf6b6b286dc65bf66641d5e9c241f4c1b147994253ac5",
"0xefc11a5944a8061c87f274515e810fee13f4c350c625a988c27ed276b6c55b6d",
"0x7a93732151f7145059424aa823b24e26341cfa57f612e6de3bddbe23562ae918",
"0x2594b625d0f5ed52425ccda4e7898a8a554300791027af6f3a19239a15868ea8",
"0x1db00091145b1b0830983b5eaa5cd3d0e4ad71c09d1b2dc20c47815bc2de5917",
"0x60563bce11f028691cf78da7326f22a4ab01d980020e61bcf2e4bdb5912b7b1d",
"0xe6515bdf1f22469a4218f54791d12698d1bc555b3e54b04cf46b10effa8ce74c",
"0x990831a56958a6bf131697e2f35ab2a45fa228eb7435c7e65814ba28778d513f",
"0x1b6e4085f0e291a8ee4d7e90158dcf15702b4e6e634d1d3bb5c4bab11bf70068",
"0xd0d4a6061bcab0f8e645ea16b285eee7f2ff84c7765d7543aa318edbced2408d",
"0x2da1a609eb1b572a47f187dd5a1e9f4cb1e1885c841f91ca82137e01a9eb4288",
"0x1293686df427f9ee1c2116000735642b3d09511cf2889dde21e1bee427d8c273",
"0x8a990d66370eaab3a46d9e4fa9b7d0c621020cd3b897d9e5b3e5fea6a6979f3c",
"0x10030534d5a06bce47d72998ad4c042f5e445a505920723d14b1d93a3a23af82",
"0xf29a399e8879386e4c2bd8e873dc8aed612cfa8dfa9e5b56f9c51d4c4d1774ad",
"0xb252062ccbb11c3181338d9912ed0d4dabcfa4d61860c211f2f702a641fe936e",
"0x822c7abd11b80c862bd67d39e16a208c8462936ca86b5cd5dd20c51d35cbfbb1",
"0x6b62aea651f1407f94906db704a364f70d827e0efba981a8515d1f515a46b266",
"0xa57b7661c0471cbd7eb35becdf468622df8338a48a075b722ebc5550bbf6b9ae",
"0xefc593d38afead5ee1fea5d8b41a52bd2a5b5a059774d0b951bb7eadaa41a46a",
"0xa556e684c26e7fd6f902b82ecdf721fc292c35e0d2240c1f362c4861c366c4c6",
"0xc9f274efc308d1e97ba9b59c92735d1ab2a72d033ed02a543dab301610e96e33",
"0xd7b43559126f88c59392fc54e2b416d2a67014abce12ddf61764df989a897bd3",
"0xc860842132de3d8c1d0ba2cdc0a7c2853ee568789f1190738862667e3539a958",
"0x2f330354084635eb507cd54549ab89fecc41886d295b1d8c91efd8ca27fe4f7d",
"0xda6edc97997b9cea1bc90662c6a8180fa03cef6189e09c86f36adb91400abe74",
"0x0d2853b5a3f02ae9e4a1c5a0534a5329d2e877d4d77f60dddb36b84b4fdf7e2f",
"0xf048b5acc9e9191ce0ab8c390bfe03d89cbed91db5b9e7c7452b01bf56bcf5ac",
"0x30fb6f6093bf59794d37ddf850c315dd9491a4cf5df378b4468dca96acf78e77",
"0xa04eeaa9d1d767c0f93553af3a259390a9576e8b6015ffa8f0e4fdf37f41f28e",
"0x02411cd53ac55407e0d31520a8c3274a2f4d1fbb2541bb140f30f25843c76860",
"0x65bc790d632d5fe2446c65325df875ba59af3c3aa7357bbbbf47c7e5f7663a7d",
"0x5f364562fed351d932eff956c3ac489ea51ad2cb12a81bd8db4fe0b76e3cbb92",
"0x104f7070d5da1aca5c8b20a96d36638e4b5f8be4e86be83f0aed7234fcece445",
"0xb2fc7a73d8d859d531e51532928671ea59ae6538d4572fd5c2d76c70920aff7f",
"0x7ebecf446825dd0010fbf47afce8b9c3b3901c839ec46269eb8744bd799699ca",
"0xc64002b5a70f18b7c51ea3d3f5246fe8db16781e146d777aaa12f3b765d108e9",
"0x9d136068c7002d2780abfefcaedc79424d3e89b17718ec369d9e64ab7b63a81f",
"0x7b9819e62e92dcead89329bcb3f1a1d6bd10794d1a22d30c3d0369a264029543",
"0x8a8c9e66f343d09d5b7897c491c851143ca4f337ddcb5c2b1462b150e22c6f47",
"0x9d86faa1a5d355d6071e09c8cca50e2dd7e7dc117c2e4f6c0136a2789e84aa8b",
"0x234e156c10a80422ca1aafd49d614e02b698a0d89a7080f87db5dd5169b419bf",
"0xafbb572b8d9119ba8126fdd5a593663db3a3e6165a60f1f439902a6321a8d243",
"0xcbfeb8af8c93b11eaddb05df2f2a8772da694f9cc16878d3154d0857f17274ae",
"0x7253cf6bd2b4d158c2bd60acf5fda9dff6cbc6468ca9b549efcd824410d2e719",
"0x67fa14af20fe738ec5c9414401149a1f198207969768a5b982454146ef720b85",
"0x6c0ddef53c7d58839c3013f2accb72190b7dcc52fbe5d71f4a20f849dd72725f",
"0x89e77c0dd9fcb4b4d4d10c25903ff5b905f5d64b6bed9a0736e9dc2035ade3eb",
"0x42466344821fc29dcdb5fe7dcbda00b3779736ca90f87ca1802207f61633877b",
"0x6e2303e8ed41e6d39488c57dff8d50c548a7079a26c3fb86d925c0aca5b8f67b",
"0xb8a14969606442bd94048f2b2dc7b87662d801097537f51c8eb8f026c52f1fe9",
"0xd7ee25e0bfd080d89c475942575fa055ce5ae268a6f01b916b399f6ff7e94a39",
"0xaf5e7da13dc0ab08ba5185074657acaa2ce753a20a364f3a97d230c247bc8d1c",
"0x92f9106bc9ccbb4e0b4c0d1b96c5bf347d856884eca91a0bcf29e896789fd9c2",
"0x4bc12bfadacd6af0737646b813b1a4a9c005e97ef4b090bb74b7475b50c85dfe",
"0x91e4ef72d0bdef33e2e2c8acbdd7926182568f559397bfc086b96979e7c4f53b",
"0xb2f57e050021b238e0b47b0b46a641644645db5bbd987e8d957038655d1fa83a",
"0xaf221401f4cfa3db7879237b40c68300060df9f65dbf68bb02694837eaa8af7a",
"0x2dd280e98a0d6bc950b7f3f0bd11a9e74105d4d15463184a3f8c03d40f3193ef",
"0x2538560e5b802a89a021685f994acbdb3181f25d0cae17160aedfc619ca2954b",
"0x133cfa3f5d6a00f7392a6b0c6a97a9ba10ec50b24cfbbe6028995258cbaa065e",
"0xc120807872f07adeb144905ff323ea79880389a2815f8441befbfa82835555b2",
"0xa2c5c5a3cbf6db506dfc13285b07c24ca7e70d9e75d80fe711c3082ba119d77a",
"0x837622b7bbb8bb18b3d42058426ef97e3fbc2842d2b64b339733b52313557562",
"0x29eda2468556699747beef75f015e6772980056cf367b819d05a4822b7d54712",
"0xc6ec29323368dc29a1d4c3c11e945ef7fdb56db78808c4c9688ab5f9eb7f27cd",
"0x44b368ab63e1fe0e0da031a4e6628ed1a4fc69fa4083cc056dd9443400be3326",
"0xf153dbc5fc03a89e80d2808ecd45e9fe6453d112508d32ffc6305d5a577d14d8",
"0x32452c0d51df7a85eac3edec46bbfe376c971ac4df4512d7e050e6fa711373ca",
"0x70cb25f3d60126cf0104a40b2a49b44ef8a42f60b93f929594938ac00647b639",
"0xed63fb33d707b93e45e958d5d5f9d3f0898c3676e43eeca55c788cbb2df3170d",
"0x93ff103a026350b0e9c2b30c36e079145892e8e3756678e8ae4b0065fb6a04ec",
"0xa466cdf6063bfe155ed75c115484ce113227385eff2cdc07dd90405239842f3f",
"0x2883c296d9ce6b1e6e7b4f471e841437603ecbb867570cbc46d86f0f26871600",
"0xea5e5b84183a3a709a51c1c6f3e7b039c4663d7495b9bdcfbd4ecb0a95ea994c",
"0xc0e97318bd3ee2957c09d6acedac77ce6b219608e5dd63ef512aa08d63c3a114",
"0xd3ccc7fcd24076afdf6249f671de402b515a131913df2da17118be47b3720b33",
"0x4f5be5a6edd66ec496207b33cefd00722f3167b9e6f2a44d9613c4c7d6541aba",
"0xfecdd1844517d0523a7b45d7b51769728902b881b7fc308f486e850c870eef5b",
"0x01a22dea1d0e25885e0a03e56489bcaf6747e712ceb5a42c74430fa6ffcc1c21",
"0x06cc521a05ce856dc55041b90dc4bbafffee578c1c315b5cfa4cc2d1ccba891f",
"0xac21d4b08fbf2891e0b3645b870695434fe703101f74e7fcf0d0e1304ce65b54",
"0xd62584c47aa1d8554cc08cf675bed128e541df54900fbfae958877595ad168ff",
"0xd8f1806ddaee8e729218fea1911efc5e663666ffb3acad4a2fda3757700d6d88",
"0x9dab2acfe01506a185276145deeecdb5c8fe0937feacffd40fb25a83e8eecc72",
"0xf0b74c6b1a441fc2ee8b2f25d2f03307164014d42a0784683a9d6cb7d2179064",
"0x7d590f0bcc891e30996adf8583803a9dd1271442c3f0e69502addbd371437767",
"0x3a66601fff95b0aa0d0660c12788ad56d2383cae290ceb2fb9ff41794abbc55a",
"0x36e94b03402f18c689f5234973ce1e626a82aac085dbdd682b51cce21f8c1872",
"0x00abd1d34c7e55f58681866558cb844c11faa55e8cac70ede75811f55341cfde",
"0x9983fc20e63e77ec0680522035b03167403681674ec62293cd6b7fe360c69157",
"0xe98b658fb8b6b7fba7463562f86348bf1e3534bc9148e8559423b3ee5ab68472"
]
},
"accounts": {

View File

@ -52,9 +52,9 @@
"extraData": "0x3535353535353535353535353535353535353535353535353535353535353535",
"gasLimit": "0x1000000"
},
"hardcodedSync": {
"header": "f90214a04d45aaeb1f0e00495b99f5fdc46c2c1e6b0fd48c693678de72afc1cb6f47a086a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794120c78af68df5957e776554d138a6b75f2c34b6ca0f2746b213421be4ec9cab40fa41aabfb4a3e8acccb6506d6cea4863774374dafa0225a348dfb2ef00db09da39b1a11b31741b6d14fd4456cdf4c2528961f398b74a09528322c1ce98449eed355ddabe0192fac920910a0d88965444b9efc1ac218eab901008000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000040000000000000000000000200000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000100000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000100000000000000000400000000000000000000000000000000000000000000000000000000000000000000008426e4d4518334e0018389545c8306529d845b284db896d583010a068650617269747986312e32362e32826c69a066f990a9ad374c2cb0017e96d3776e6c787f679d77c9079fe2b046279453d0f88851bec8da753bda19",
"totalDifficulty": "8635599198809021",
"hardcodedSync":{
"header": "f90213a0f6a1b2e8155af1d1d77879826e2535cb6023ba35705934380ab05f65bcbfb107a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794f3af96f89b3d7cdcbe0c083690a28185feb0b3cea015ca95dffe4c5de6d9c02d9282df0db94855b0d602738f4b6fcb2268694cd92aa07ecb0900077c45bd4d3ca910218099f726fea18461f90be18897710767a51559a0251f2cb798e965c5d9b11c882f37c69fd2c42b314fabe64d2b4998c76eb93ae8b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008439b475f9833720018389769d82f618845b45928b96d583010b038650617269747986312e32362e31826c69a0fbd0db05012df54423a6b25395ec4f6e66d9f11af8b9c492c4fb7197fcd6a5ba8877d4a227c2bdf4de",
"totalDifficulty": "8809217991079619",
"CHTs": [
"0x614648fc0a459451850bdfe353a932b5ff824e1b568478394f78b3ed5427e37a",
"0x1eae561c582dbb7f4e041998e084e165d0332c915d3a6da367638a8d24f3fafc",
@ -1747,7 +1747,79 @@
"0x8baa0703e1a050c40f85dc850fe477881f432c951b1cc1b2b71ffb68ab7fe0d7",
"0x14ca94dfd343548e32ef5659c043d6e28f0e577fd38da1ee12f11c08e281d775",
"0xef25357970c76a8b72a6e52f49bc30651f711c7df70444d4667e80febc0e3b2a",
"0x41b8b4ebd5919dad3bc609ded524b97403d88f019367f0f4f622561131644ffb"
"0x41b8b4ebd5919dad3bc609ded524b97403d88f019367f0f4f622561131644ffb",
"0xb29a8ad1157621d0120aedbd8dfeb4b318979bd43a5b018bf7b9ce33d85da312",
"0x9ddf78b5d67ef40454867ed33de83a01cbd8c18fe09da3d9f991a196811dfccd",
"0x3604121f9cfbb5cf552cf8bfc9a7958332eb97131158e4f40f4eda481e553991",
"0xf1778830f694720a6f990f9d476b0f365e8a74880253b55ee16f5cbd6c8082a4",
"0x89831626d154fbe84a4c62c3e2638cd00e42b3844c7c7b98cfad113abdbc5347",
"0x650573f5ef274b2aeb40642e25fbd661cb0eff66245d7cc8f6fb9e9daa80fc12",
"0x479f6c652173efe94abaa850bffe1557847b26f286467013a4d72973e05e8e54",
"0x7096619d5716c34592ac2d9907ac28a74c6f6b1ebb1962a0217df82bf3e714d4",
"0xb7c7edbd8ae7eed58e973dc0750adfd04042ed56baabf372b111fce3e4b4469a",
"0x25529b597bd15317e55767b3fbfecad0657aaeda99f098186b41b70811f7af2a",
"0xd790747b09f925fd155b7bbdb5ccd89d873277163e4fe7054bbf71c0b26b8072",
"0x3aa0b221d1c4743a06692f645f38a8128d55f1c07cfa6e9711b0d2e0f2e0e738",
"0x26fb5017218cbe4250d2ceae751e99b9a34d7befa162dc248ac008c5d1221e71",
"0x0e4ada59854027601f8f81fbdceb95228db667eb65fed97cefbb35dba21d3b52",
"0xd3be75ae2da3e271dd85cd8226d789aa12d108a4b0d2681462f6539637572e50",
"0x6f041891c8219b508138f67c95a1765d08c5ec06b9ce585f52f837806fce0609",
"0x9e106515d0e80b41397b2e8e98adbb7333e76265917339a62063a07d9a7ed311",
"0x25f47483ecc5ec32f94b3dbcb4d42a4cdbf5c279e93567e14afc742a4619d3e0",
"0x5d81afc54f6b68bd820dcc629ff7e9d8397da56ffedef9addab0eec620de0757",
"0x36e192130485f248925d4b0d2fd98745a76099eb13f53093621d216d0aff0d6c",
"0xb906e5e33b63f6cc355c13b8461a260ee25376ee96909fad2c6ac121ad831496",
"0xd68e7e0d136e30f67ccb7c21e4dc43b0ad5536584e4b77c9da8d903a04e9d212",
"0x5aa7847a4bddda7fbffa62325da920a21a11524ac1b691bc3b55e4d1790f24bc",
"0x331f95f062ed1d38dd02b5ab6a95dd238ef97c5ee9777c938697340c902b4b5d",
"0x8c6a580c8b07567f747bf20946023c3b581c51075cce5cd5d47b0d81d8922135",
"0x8b89483810a49626f90846a0b49ad3e2172657dfa3003d58fa2a43d12c8f4090",
"0x944f9a5754800a33d903c8a464d602fc9da6af8ff3990c3eb669ac9cd17891f9",
"0xc75c82a2c1ecd875d16f343a58835d756740902c246d3b1deae97e49aa19f98b",
"0x1d2e0f2f87ff2b08514b18855c343966d42e0f1a048ddd3d316dca6e06292db9",
"0xa6508507463e53b3a840dd55ed9be57c8a56e1533c9001276750bdf19796f8ea",
"0x01eb6b636b1852e8f9066c12d4e6b7b06b90a325be4d97e08f7f560bab4796a1",
"0x8a0d77fb41f50808ff0a46dc9f3831a2b5093f55ec2e94a3d2e92373ff3b5695",
"0xea3383ba1d30891d1e236db2b31373541f51a9e5c4b4d017cc4960480dd20311",
"0x01129e8d7eff516a225cc0db090e4e38362d9eb2d0571ce00f4417836de2e375",
"0x92feaefb7f9466814a0220e536fe5ee73560507d071e059827d406329e609f87",
"0xac149150c11b3bdc660320a0e955f154fa3137549a73951207659e2b903c145b",
"0xcb68cdb224f9b3b0b0f3ca0056e70817146c9ebc75876dd952e6ca8ea896f2ac",
"0x157565282a12d790452e343c9762c2124456039729f3a8f97a2cee60d85628fa",
"0x42eadc181d59d8d8b26b37e0e9c9052e45bde72090d330bf9cf21d9d3c7d9048",
"0x1ea0ec8879b200e259a3a2a0f2a7aa292301784fa422f7c32ed5d945183948b2",
"0x06aeb2956be9d74ae4ff0b8a6c1874ed8ba46a186616356dc060bea1cbe5c628",
"0x814b0382b52a155a4e35639aeb3d8c859afc4fe5d151de3b0f1bac646e40f2eb",
"0xb30bf3e85be41a2a9e53321ee9f03c7078516c72c7e2d8e7e3134de709b61c36",
"0x1f97f5d334b5e6ebc72f5b846f24c7911f4fd1653f89b3477ce4b8108342810f",
"0x84c6fd181c28ad159ff18d203d14f966668468c9ef0a5d6dbd863886a7e0af1e",
"0x4b2e6947d55ea504bf205bae9dfc0e5402efd33757eea4da00a8ed2a6a3838ae",
"0x85f31d45128bb91cd3490b58a0a641ef77246ea9c83de30fa89b621307fd96f3",
"0xd362f5e6f8cbb216e66eaf49e4df25e01504ac729da86c530871a34e11d302f6",
"0xb7860983b043bc13ce5a27135eea12ffaeff71879404b18af3079b98da156bf2",
"0xf2ff82a679b2b90cb9f4a3bb903eb7ab36ee1c47cbe40024d8d570f5e16bbf4e",
"0x7e34a7e6673146b6bb7f78593b6093ef15b8e9fd1271b33dc5f7d17876b31871",
"0x725c97f83b4cf213296ef353e1c8d64854ef08983fd61320088b8d9e2ab33849",
"0x18085800d10fc7845148835d0ef0ac980a82eeafc44e12bfa296f9c38fc6e19d",
"0xc6c3cf95310cfd0254f0f8e93a3c25bad2b17df04f9c51a25927b80d02e06b69",
"0x822213c1b03cf68ecadc0b7572d37266207d5fe4efd5e56a924b0a1aab8a8e84",
"0x1ff46ffd2dd880cca76244f6af1fd8bddbb4b9ec58f86639821a16f2ff08f3a8",
"0xe9d00df19d716dc859922f2e6c907263191c8e531498ea557869ea1115317c95",
"0x6d3f1edebd562e9d1a236ed7a1d9104fd8f5a086cd78d35c7a65f27c269d98ca",
"0xfea701ced5bca0d5043512700598d3eafa0b89dc02f3c157cd1d52bcf4d84d9b",
"0x556c1cd8ff3ebc2ccd4eee9f1ad3837e346ecda961da17c0ee9cd4d084a47653",
"0x5606be2fba065424af76c94d4156ea82f77d9872ddac7a4c2517957a169e58f9",
"0x8d0223425b48487db1b371c966c7688435f4b9fcda75b088f0aac203d6657cb1",
"0xfceb55d8f3048a3f2255562e0a9ee342439253abcd048fac151ef4b910048e22",
"0x360f76e4f2ef49632e3bf8cfc3afeccff6917e98a48d3568148c3bb13f9d2d7e",
"0xd87bbf8397204cc2af883362646b0ae95392303935ec1997ab052c194e0ef117",
"0x9f1dad9dfecaaf117ab5277caf672b70540578e703c2024d3f23bb7cf8d6410b",
"0x5e130ccb23b7b66dd2fbdd912d6006d2820071dafe2890f593f952028aaa19c0",
"0xccd2f182107992fb9b002b87cdf7990cb2810b202b2ae5d6ef5e0b3bd69632e2",
"0x4b40cd83205f8b946ca9f11fc3306872650e658e631511fd4080bc8ca749d913",
"0x652acc59b71ca20bb65ca195d1a4b3e177f6a3985bdcd6120e1a45b7d4a0c7ca",
"0x49a5e2580ceb329665244e489592aea27d54da8189a665d9435e037ea70c46a5",
"0x379801356beb3a8e5fa7311792c69c7ac1f675a9c08c837f9f0e9f53c243d6a7"
]
},
"nodes": [

View File

@ -94,6 +94,7 @@ impl ClientService {
let pruning = config.pruning;
let client = Client::new(config, &spec, blockchain_db.clone(), miner.clone(), io_service.channel())?;
miner.set_io_channel(io_service.channel());
let snapshot_params = SnapServiceParams {
engine: spec.engine.clone(),

View File

@ -200,7 +200,7 @@ pub struct Client {
/// Flag changed by `sleep` and `wake_up` methods. Not to be confused with `enabled`.
liveness: AtomicBool,
io_channel: Mutex<IoChannel<ClientIoMessage>>,
io_channel: RwLock<IoChannel<ClientIoMessage>>,
/// List of actors to be notified on certain chain events
notify: RwLock<Vec<Weak<ChainNotify>>>,
@ -761,7 +761,7 @@ impl Client {
db: RwLock::new(db.clone()),
state_db: RwLock::new(state_db),
report: RwLock::new(Default::default()),
io_channel: Mutex::new(message_channel),
io_channel: RwLock::new(message_channel),
notify: RwLock::new(Vec::new()),
queue_transactions: IoChannelQueue::new(config.transaction_verification_queue_size),
queue_ancient_blocks: IoChannelQueue::new(MAX_ANCIENT_BLOCKS_QUEUE_SIZE),
@ -995,7 +995,7 @@ impl Client {
/// Replace io channel. Useful for testing.
pub fn set_io_channel(&self, io_channel: IoChannel<ClientIoMessage>) {
*self.io_channel.lock() = io_channel;
*self.io_channel.write() = io_channel;
}
/// Get a copy of the best block's state.
@ -2011,7 +2011,7 @@ impl IoClient for Client {
fn queue_transactions(&self, transactions: Vec<Bytes>, peer_id: usize) {
trace_time!("queue_transactions");
let len = transactions.len();
self.queue_transactions.queue(&mut self.io_channel.lock(), len, move |client| {
self.queue_transactions.queue(&self.io_channel.read(), len, move |client| {
trace_time!("import_queued_transactions");
let txs: Vec<UnverifiedTransaction> = transactions
@ -2060,7 +2060,7 @@ impl IoClient for Client {
let queued = self.queued_ancient_blocks.clone();
let lock = self.ancient_blocks_import_lock.clone();
match self.queue_ancient_blocks.queue(&mut self.io_channel.lock(), 1, move |client| {
match self.queue_ancient_blocks.queue(&self.io_channel.read(), 1, move |client| {
trace_time!("import_ancient_block");
// Make sure to hold the lock here to prevent importing out of order.
// We use separate lock, cause we don't want to block queueing.
@ -2092,7 +2092,7 @@ impl IoClient for Client {
}
fn queue_consensus_message(&self, message: Bytes) {
match self.queue_consensus_message.queue(&mut self.io_channel.lock(), 1, move |client| {
match self.queue_consensus_message.queue(&self.io_channel.read(), 1, move |client| {
if let Err(e) = client.engine().handle_message(&message) {
debug!(target: "poa", "Invalid message received: {}", e);
}
@ -2202,7 +2202,14 @@ impl ImportSealedBlock for Client {
route
};
let route = ChainRoute::from([route].as_ref());
self.importer.miner.chain_new_blocks(self, &[h.clone()], &[], route.enacted(), route.retracted(), self.engine.seals_internally().is_some());
self.importer.miner.chain_new_blocks(
self,
&[h.clone()],
&[],
route.enacted(),
route.retracted(),
self.engine.seals_internally().is_some(),
);
self.notify(|notify| {
notify.new_blocks(
vec![h.clone()],
@ -2526,7 +2533,7 @@ impl IoChannelQueue {
}
}
pub fn queue<F>(&self, channel: &mut IoChannel<ClientIoMessage>, count: usize, fun: F) -> Result<(), QueueError> where
pub fn queue<F>(&self, channel: &IoChannel<ClientIoMessage>, count: usize, fun: F) -> Result<(), QueueError> where
F: Fn(&Client) + Send + Sync + 'static,
{
let queue_size = self.currently_queued.load(AtomicOrdering::Relaxed);

View File

@ -280,11 +280,18 @@ impl Engine<EthereumMachine> for Arc<Ethash> {
block_reward::apply_block_rewards(&rewards, block, &self.machine)
}
#[cfg(not(feature = "miner-debug"))]
fn verify_local_seal(&self, header: &Header) -> Result<(), Error> {
self.verify_block_basic(header)
.and_then(|_| self.verify_block_unordered(header))
}
#[cfg(feature = "miner-debug")]
fn verify_local_seal(&self, _header: &Header) -> Result<(), Error> {
warn!("Skipping seal verification, running in miner testing mode.");
Ok(())
}
fn verify_block_basic(&self, header: &Header) -> Result<(), Error> {
// check the seal fields.
let seal = Seal::parse_seal(header.seal())?;

View File

@ -28,6 +28,7 @@ use ethcore_miner::pool::{self, TransactionQueue, VerifiedTransaction, QueueStat
#[cfg(feature = "work-notify")]
use ethcore_miner::work_notify::NotifyWork;
use ethereum_types::{H256, U256, Address};
use io::IoChannel;
use parking_lot::{Mutex, RwLock};
use rayon::prelude::*;
use transaction::{
@ -44,7 +45,7 @@ use block::{ClosedBlock, IsBlock, Block, SealedBlock};
use client::{
BlockChain, ChainInfo, CallContract, BlockProducer, SealedBlockImporter, Nonce
};
use client::BlockId;
use client::{BlockId, ClientIoMessage};
use executive::contract_address;
use header::{Header, BlockNumber};
use miner;
@ -96,7 +97,7 @@ const DEFAULT_MINIMAL_GAS_PRICE: u64 = 20_000_000_000;
/// before stopping attempts to push more transactions to the block.
/// This is an optimization that prevents traversing the entire pool
/// in case we have only a fraction of available block gas limit left.
const MAX_SKIPPED_TRANSACTIONS: usize = 8;
const MAX_SKIPPED_TRANSACTIONS: usize = 128;
/// Configures the behaviour of the miner.
#[derive(Debug, PartialEq)]
@ -211,6 +212,7 @@ pub struct Miner {
transaction_queue: Arc<TransactionQueue>,
engine: Arc<EthEngine>,
accounts: Option<Arc<AccountProvider>>,
io_channel: RwLock<Option<IoChannel<ClientIoMessage>>>,
}
impl Miner {
@ -227,7 +229,12 @@ impl Miner {
}
/// Creates new instance of miner Arc.
pub fn new(options: MinerOptions, gas_pricer: GasPricer, spec: &Spec, accounts: Option<Arc<AccountProvider>>) -> Self {
pub fn new(
options: MinerOptions,
gas_pricer: GasPricer,
spec: &Spec,
accounts: Option<Arc<AccountProvider>>,
) -> Self {
let limits = options.pool_limits.clone();
let verifier_options = options.pool_verification_options.clone();
let tx_queue_strategy = options.tx_queue_strategy;
@ -251,6 +258,7 @@ impl Miner {
transaction_queue: Arc::new(TransactionQueue::new(limits, verifier_options, tx_queue_strategy)),
accounts,
engine: spec.engine.clone(),
io_channel: RwLock::new(None),
}
}
@ -270,6 +278,11 @@ impl Miner {
}, GasPricer::new_fixed(minimal_gas_price), spec, accounts)
}
/// Sets `IoChannel`
pub fn set_io_channel(&self, io_channel: IoChannel<ClientIoMessage>) {
*self.io_channel.write() = Some(io_channel);
}
/// Clear all pending block states
pub fn clear(&self) {
self.sealing.lock().queue.reset();
@ -384,7 +397,7 @@ impl Miner {
let max_transactions = if min_tx_gas.is_zero() {
usize::max_value()
} else {
(*open_block.block().header().gas_limit() / min_tx_gas).as_u64() as usize
MAX_SKIPPED_TRANSACTIONS.saturating_add((*open_block.block().header().gas_limit() / min_tx_gas).as_u64() as usize)
};
let pending: Vec<Arc<_>> = self.transaction_queue.pending(
@ -1176,7 +1189,32 @@ impl miner::MinerService for Miner {
// (thanks to Ready), but culling can take significant amount of time,
// so best to leave it after we create some work for miners to prevent increased
// uncle rate.
self.transaction_queue.cull(client);
// If the io_channel is available attempt to offload culling to a separate task
// to avoid blocking chain_new_blocks
if let Some(ref channel) = *self.io_channel.read() {
let queue = self.transaction_queue.clone();
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 cull = move |chain: &::client::Client| {
let client = PoolClient::new(
chain,
&nonce_cache,
&*engine,
accounts.as_ref().map(|x| &**x),
refuse_service_transactions,
);
queue.cull(client);
};
if let Err(e) = channel.send(ClientIoMessage::execute(cull)) {
warn!(target: "miner", "Error queueing cull: {:?}", e);
}
} else {
self.transaction_queue.cull(client);
}
}
}

View File

@ -16,8 +16,11 @@
//! Blockchain access for transaction pool.
use std::fmt;
use std::collections::HashMap;
use std::{
collections::HashMap,
fmt,
sync::Arc,
};
use ethereum_types::{H256, U256, Address};
use ethcore_miner::pool;
@ -37,9 +40,9 @@ use miner;
use miner::service_transaction_checker::ServiceTransactionChecker;
/// Cache for state nonces.
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct NonceCache {
nonces: RwLock<HashMap<Address, U256>>,
nonces: Arc<RwLock<HashMap<Address, U256>>>,
limit: usize
}
@ -47,7 +50,7 @@ impl NonceCache {
/// Create new cache with a limit of `limit` entries.
pub fn new(limit: usize) -> Self {
NonceCache {
nonces: RwLock::new(HashMap::with_capacity(limit / 2)),
nonces: Arc::new(RwLock::new(HashMap::with_capacity(limit / 2))),
limit,
}
}

View File

@ -477,18 +477,19 @@ impl BlockDownloader {
for block_and_receipts in blocks {
let block = block_and_receipts.block;
let receipts = block_and_receipts.receipts;
// Perform basic block verification
if !Block::is_good(&block) {
debug!(target: "sync", "Bad block rlp: {:?}", block);
bad = true;
break;
}
let (h, number, parent) = {
let header = view!(BlockView, &block).header_view();
(header.hash(), header.number(), header.parent_hash())
};
// Perform basic block verification
if !Block::is_good(&block) {
debug!(target: "sync", "Bad block rlp {:?} : {:?}", h, block);
bad = true;
break;
}
if self.target_hash.as_ref().map_or(false, |t| t == &h) {
self.state = State::Complete;
trace!(target: "sync", "Sync target reached");

View File

@ -939,7 +939,13 @@ impl Configuration {
let is_using_base_path = self.args.arg_base_path.is_some();
// If base_path is set and db_path is not we default to base path subdir instead of LOCAL.
let base_db_path = if is_using_base_path && self.args.arg_db_path.is_none() {
"$BASE/chains"
if self.args.flag_light {
"$BASE/chains_light"
} else {
"$BASE/chains"
}
} else if self.args.flag_light {
self.args.arg_db_path.as_ref().map_or(dir::CHAINS_PATH_LIGHT, |s| &s)
} else {
self.args.arg_db_path.as_ref().map_or(dir::CHAINS_PATH, |s| &s)
};

View File

@ -20,7 +20,6 @@ use std::str::FromStr;
use std::sync::{Arc, Weak};
pub use parity_rpc::signer::SignerService;
pub use parity_rpc::dapps::LocalDapp;
use ethcore_service::PrivateTxService;
use ethcore::account_provider::AccountProvider;

View File

@ -33,7 +33,6 @@ use ethcore_logger::{Config as LogConfig, RotatingLogger};
use ethcore_service::ClientService;
use ethereum_types::Address;
use sync::{self, SyncConfig};
#[cfg(feature = "work-notify")]
use miner::work_notify::WorkPoster;
use futures::IntoFuture;
use futures_cpupool::CpuPool;
@ -504,19 +503,17 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
cmd.miner_options,
cmd.gas_pricer_conf.to_gas_pricer(fetch.clone(), cpu_pool.clone()),
&spec,
Some(account_provider.clone())
Some(account_provider.clone()),
));
miner.set_author(cmd.miner_extras.author, None).expect("Fails only if password is Some; password is None; qed");
miner.set_gas_range_target(cmd.miner_extras.gas_range_target);
miner.set_extra_data(cmd.miner_extras.extra_data);
#[cfg(feature = "work-notify")]
{
if !cmd.miner_extras.work_notify.is_empty() {
miner.add_work_listener(Box::new(
WorkPoster::new(&cmd.miner_extras.work_notify, fetch.clone(), event_loop.remote())
));
}
if !cmd.miner_extras.work_notify.is_empty() {
miner.add_work_listener(Box::new(
WorkPoster::new(&cmd.miner_extras.work_notify, fetch.clone(), event_loop.remote())
));
}
let engine_signer = cmd.miner_extras.engine_signer;

View File

@ -17,12 +17,13 @@
//! Parity upgrade logic
use semver::{Version, SemVerError};
use std::collections::HashMap;
use std::collections::*;
use std::fs::{self, File, create_dir_all};
use std::env;
use std::io;
use std::io::{Read, Write};
use std::path::{PathBuf, Path};
use dir::{DatabaseDirectories, default_data_path, home_dir};
use dir::{DatabaseDirectories, default_data_path};
use dir::helpers::replace_home;
use journaldb::Algorithm;
@ -105,7 +106,7 @@ fn with_locked_version<F>(db_path: Option<&str>, script: F) -> Result<usize, Err
where F: Fn(&Version) -> Result<usize, Error>
{
let mut path = db_path.map_or({
let mut path = home_dir().expect("Applications should have a home dir");
let mut path = env::home_dir().expect("Applications should have a home dir");
path.push(".parity");
path
}, PathBuf::from);

View File

@ -118,7 +118,7 @@ pub use http::{
AccessControlAllowOrigin, Host, DomainsValidation
};
pub use v1::{NetworkSettings, Metadata, Origin, informant, dispatch, signer, dapps};
pub use v1::{NetworkSettings, Metadata, Origin, informant, dispatch, signer};
pub use v1::block_import::is_major_importing;
pub use v1::extractors::{RpcExtractor, WsExtractor, WsStats, WsDispatcher};
pub use authcodes::{AuthCodes, TimeProvider};

View File

@ -1,27 +0,0 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Dapps Service
use v1::types::LocalDapp;
/// Dapps Server service.
pub trait DappsService: Send + Sync + 'static {
/// List available local dapps.
fn list_dapps(&self) -> Vec<LocalDapp>;
/// Refresh local dapps list
fn refresh_local_dapps(&self) -> bool;
}

View File

@ -211,14 +211,6 @@ pub fn signer_disabled() -> Error {
}
}
pub fn dapps_disabled() -> Error {
Error {
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
message: "Dapps Server is disabled. This API is not available.".into(),
data: None,
}
}
pub fn ws_disabled() -> Error {
Error {
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),

View File

@ -18,7 +18,6 @@
pub mod errors;
pub mod block_import;
pub mod dapps;
pub mod dispatch;
pub mod fake_sign;
pub mod ipfs;

View File

@ -326,10 +326,6 @@ impl Parity for ParityClient {
Ok(map)
}
fn dapps_url(&self) -> Result<String> {
Err(errors::dapps_disabled())
}
fn ws_url(&self) -> Result<String> {
helpers::to_url(&self.ws_address)
.ok_or_else(|| errors::ws_disabled())

View File

@ -29,7 +29,7 @@ use jsonrpc_core::{Result, BoxFuture};
use jsonrpc_core::futures::Future;
use v1::helpers::errors;
use v1::traits::ParitySet;
use v1::types::{Bytes, H160, H256, U256, ReleaseInfo, Transaction, LocalDapp};
use v1::types::{Bytes, H160, H256, U256, ReleaseInfo, Transaction};
/// Parity-specific rpc interface for operations altering the settings.
pub struct ParitySetClient<F> {
@ -137,14 +137,6 @@ impl<F: Fetch> ParitySet for ParitySetClient<F> {
Box::new(self.pool.spawn(future))
}
fn dapps_refresh(&self) -> Result<bool> {
Err(errors::dapps_disabled())
}
fn dapps_list(&self) -> Result<Vec<LocalDapp>> {
Err(errors::dapps_disabled())
}
fn upgrade_ready(&self) -> Result<Option<ReleaseInfo>> {
Err(errors::light_unimplemented(None))
}

View File

@ -347,10 +347,6 @@ impl<C, M, U, S> Parity for ParityClient<C, M, U> where
)
}
fn dapps_url(&self) -> Result<String> {
Err(errors::dapps_disabled())
}
fn ws_url(&self) -> Result<String> {
helpers::to_url(&self.ws_address)
.ok_or_else(|| errors::ws_disabled())

View File

@ -31,7 +31,7 @@ use jsonrpc_core::{BoxFuture, Result};
use jsonrpc_core::futures::Future;
use v1::helpers::errors;
use v1::traits::ParitySet;
use v1::types::{Bytes, H160, H256, U256, ReleaseInfo, Transaction, LocalDapp};
use v1::types::{Bytes, H160, H256, U256, ReleaseInfo, Transaction};
/// Parity-specific rpc interface for operations altering the settings.
pub struct ParitySetClient<C, M, U, F = fetch::Client> {
@ -182,14 +182,6 @@ impl<C, M, U, F> ParitySet for ParitySetClient<C, M, U, F> where
Box::new(self.pool.spawn(future))
}
fn dapps_refresh(&self) -> Result<bool> {
Err(errors::dapps_disabled())
}
fn dapps_list(&self) -> Result<Vec<LocalDapp>> {
Err(errors::dapps_disabled())
}
fn upgrade_ready(&self) -> Result<Option<ReleaseInfo>> {
Ok(self.updater.upgrade_ready().map(Into::into))
}

View File

@ -53,9 +53,3 @@ pub mod signer {
pub use super::helpers::{SigningQueue, SignerService, ConfirmationsQueue};
pub use super::types::{ConfirmationRequest, TransactionModification, U256, TransactionCondition};
}
/// Dapps integration utilities
pub mod dapps {
pub use super::helpers::dapps::DappsService;
pub use super::types::LocalDapp;
}

View File

@ -425,20 +425,6 @@ fn rpc_parity_ws_address() {
assert_eq!(io2.handle_request_sync(request), Some(response2.to_owned()));
}
#[test]
fn rpc_parity_dapps_address() {
// given
let deps = Dependencies::new();
let io1 = deps.default_client();
// when
let request = r#"{"jsonrpc": "2.0", "method": "parity_dappsUrl", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","error":{"code":-32000,"message":"Dapps Server is disabled. This API is not available."},"id":1}"#;
// then
assert_eq!(io1.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_parity_next_nonce() {
let deps = Dependencies::new();

View File

@ -238,18 +238,3 @@ fn rpc_parity_remove_transaction() {
miner.pending_transactions.lock().insert(hash, signed);
assert_eq!(io.handle_request_sync(&request), Some(response.to_owned()));
}
#[test]
fn rpc_parity_set_dapps_list() {
let miner = miner_service();
let client = client_service();
let network = network_service();
let updater = updater_service();
let mut io = IoHandler::new();
io.extend_with(parity_set_client(&client, &miner, &updater, &network).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "parity_dappsList", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","error":{"code":-32000,"message":"Dapps Server is disabled. This API is not available."},"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}

View File

@ -161,11 +161,6 @@ build_rpc_trait! {
#[rpc(name = "parity_localTransactions")]
fn local_transactions(&self) -> Result<BTreeMap<H256, LocalTransactionStatus>>;
/// Returns current Dapps Server interface and port or an error if dapps server is disabled.
/// (deprecated, should always return an error now).
#[rpc(name = "parity_dappsUrl")]
fn dapps_url(&self) -> Result<String>;
/// Returns current WS Server interface and port or an error if ws server is disabled.
#[rpc(name = "parity_wsUrl")]
fn ws_url(&self) -> Result<String>;

View File

@ -18,7 +18,7 @@
use jsonrpc_core::{BoxFuture, Result};
use v1::types::{Bytes, H160, H256, U256, ReleaseInfo, Transaction, LocalDapp};
use v1::types::{Bytes, H160, H256, U256, ReleaseInfo, Transaction};
build_rpc_trait! {
/// Parity-specific rpc interface for operations altering the settings.
@ -95,15 +95,6 @@ build_rpc_trait! {
#[rpc(name = "parity_hashContent")]
fn hash_content(&self, String) -> BoxFuture<H256>;
/// Returns true if refresh successful, error if unsuccessful or server is disabled
/// (deprecated, should always return an error now).
#[rpc(name = "parity_dappsRefresh")]
fn dapps_refresh(&self) -> Result<bool>;
/// Returns a list of local dapps (deprecated, should always return an error now).
#[rpc(name = "parity_dappsList")]
fn dapps_list(&self) -> Result<Vec<LocalDapp>>;
/// Is there a release ready for install?
#[rpc(name = "parity_upgradeReady")]
fn upgrade_ready(&self) -> Result<Option<ReleaseInfo>>;

View File

@ -1,61 +0,0 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
/// Local Dapp
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct LocalDapp {
/// ID of local dapp
pub id: String,
/// Dapp name
pub name: String,
/// Dapp description
pub description: String,
/// Dapp version string
pub version: String,
/// Dapp author
pub author: String,
/// Dapp icon
#[serde(rename="iconUrl")]
pub icon_url: String,
/// Local development Url
#[serde(rename="localUrl")]
pub local_url: Option<String>,
}
#[cfg(test)]
mod tests {
use serde_json;
use super::LocalDapp;
#[test]
fn dapp_serialization() {
let s = r#"{"id":"skeleton","name":"Skeleton","description":"A skeleton dapp","version":"0.1","author":"Parity Technologies Ltd","iconUrl":"title.png","localUrl":"http://localhost:5000"}"#;
let dapp = LocalDapp {
id: "skeleton".into(),
name: "Skeleton".into(),
description: "A skeleton dapp".into(),
version: "0.1".into(),
author: "Parity Technologies Ltd".into(),
icon_url: "title.png".into(),
local_url: Some("http://localhost:5000".into()),
};
let serialized = serde_json::to_string(&dapp).unwrap();
assert_eq!(serialized, s);
}
}

View File

@ -23,7 +23,6 @@ mod bytes;
mod call_request;
mod confirmations;
mod consensus_status;
mod dapps;
mod derivation;
mod filter;
mod hash;
@ -57,7 +56,6 @@ pub use self::confirmations::{
TransactionModification, SignRequest, DecryptRequest, Either
};
pub use self::consensus_status::*;
pub use self::dapps::LocalDapp;
pub use self::derivation::{DeriveHash, DeriveHierarchical, Derive};
pub use self::filter::{Filter, FilterChanges};
pub use self::hash::{H64, H160, H256, H512, H520, H2048};

View File

@ -33,7 +33,7 @@ parts:
# rust-channel: stable # @TODO enable after https://bugs.launchpad.net/snapcraft/+bug/1778530
rust-revision: 1.26.2 # @TODO remove after https://bugs.launchpad.net/snapcraft/+bug/1778530
build-attributes: [no-system-libraries]
build-packages: [g++, libudev-dev, libssl-dev, make, pkg-config]
build-packages: [g++, libudev-dev, libssl-dev, make, pkg-config, cmake]
stage-packages: [libc6, libssl1.0.0, libudev1, libstdc++6]
df:
plugin: nil

View File

@ -8,4 +8,3 @@ license = "GPL3"
ethereum-types = "0.3"
journaldb = { path = "../journaldb" }
app_dirs = { git = "https://github.com/paritytech/app-dirs-rs" }
dirs = "1.0.2"

View File

@ -15,11 +15,12 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Directory helper functions
use std::env;
/// Replaces `$HOME` str with home directory path.
pub fn replace_home(base: &str, arg: &str) -> String {
// the $HOME directory on mac os should be `~/Library` or `~/Library/Application Support`
let r = arg.replace("$HOME", ::dirs::home_dir().unwrap().to_str().unwrap());
let r = arg.replace("$HOME", env::home_dir().unwrap().to_str().unwrap());
let r = r.replace("$BASE", base);
r.replace("/", &::std::path::MAIN_SEPARATOR.to_string())
}

View File

@ -18,12 +18,11 @@
//! Dir utilities for platform-specific operations
extern crate app_dirs;
extern crate dirs;
extern crate ethereum_types;
extern crate journaldb;
pub mod helpers;
use std::fs;
use std::{env, fs};
use std::path::{PathBuf, Path};
use ethereum_types::{H64, H256};
use journaldb::Algorithm;
@ -32,12 +31,14 @@ use app_dirs::{AppInfo, get_app_root, AppDataType};
// re-export platform-specific functions
use platform::*;
pub use dirs::home_dir;
/// Platform-specific chains path - Windows only
/// Platform-specific chains path for standard client - Windows only
#[cfg(target_os = "windows")] pub const CHAINS_PATH: &str = "$LOCAL/chains";
/// Platform-specific chains path
/// Platform-specific chains path for light client - Windows only
#[cfg(target_os = "windows")] pub const CHAINS_PATH_LIGHT: &str = "$LOCAL/chains_light";
/// Platform-specific chains path for standard client
#[cfg(not(target_os = "windows"))] pub const CHAINS_PATH: &str = "$BASE/chains";
/// Platform-specific chains path for light client
#[cfg(not(target_os = "windows"))] pub const CHAINS_PATH_LIGHT: &str = "$BASE/chains_light";
/// Platform-specific cache path - Windows only
#[cfg(target_os = "windows")] pub const CACHE_PATH: &str = "$LOCAL/cache";
@ -236,7 +237,7 @@ pub fn default_hypervisor_path() -> PathBuf {
/// Get home directory.
fn home() -> PathBuf {
dirs::home_dir().expect("Failed to get home dir")
env::home_dir().expect("Failed to get home dir")
}
/// Geth path
@ -259,9 +260,9 @@ pub fn parity(chain: &str) -> PathBuf {
#[cfg(target_os = "macos")]
mod platform {
use std::path::PathBuf;
pub const AUTHOR: &'static str = "Parity";
pub const PRODUCT: &'static str = "io.parity.ethereum";
pub const PRODUCT_HYPERVISOR: &'static str = "io.parity.ethereum-updates";
pub const AUTHOR: &str = "Parity";
pub const PRODUCT: &str = "io.parity.ethereum";
pub const PRODUCT_HYPERVISOR: &str = "io.parity.ethereum-updates";
pub fn parity_base() -> PathBuf {
let mut home = super::home();
@ -283,9 +284,9 @@ mod platform {
#[cfg(windows)]
mod platform {
use std::path::PathBuf;
pub const AUTHOR: &'static str = "Parity";
pub const PRODUCT: &'static str = "Ethereum";
pub const PRODUCT_HYPERVISOR: &'static str = "EthereumUpdates";
pub const AUTHOR: &str = "Parity";
pub const PRODUCT: &str = "Ethereum";
pub const PRODUCT_HYPERVISOR: &str = "EthereumUpdates";
pub fn parity_base() -> PathBuf {
let mut home = super::home();

View File

@ -17,11 +17,12 @@
use parity_bytes::Bytes;
use std::net::SocketAddr;
use std::collections::{HashSet, HashMap, VecDeque};
use std::collections::hash_map::Entry;
use std::default::Default;
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
use hash::keccak;
use ethereum_types::{H256, H520};
use rlp::{Rlp, RlpStream, encode_list};
use rlp::{Rlp, RlpStream};
use node_table::*;
use network::{Error, ErrorKind};
use ethkey::{Secret, KeyPair, sign, recover};
@ -42,7 +43,15 @@ const PACKET_FIND_NODE: u8 = 3;
const PACKET_NEIGHBOURS: u8 = 4;
const PING_TIMEOUT: Duration = Duration::from_millis(300);
const FIND_NODE_TIMEOUT: Duration = Duration::from_secs(2);
const EXPIRY_TIME: Duration = Duration::from_secs(60);
const MAX_NODES_PING: usize = 32; // Max nodes to add/ping at once
const REQUEST_BACKOFF: [Duration; 4] = [
Duration::from_secs(1),
Duration::from_secs(4),
Duration::from_secs(16),
Duration::from_secs(64)
];
#[derive(Clone, Debug)]
pub struct NodeEntry {
@ -53,13 +62,35 @@ pub struct NodeEntry {
pub struct BucketEntry {
pub address: NodeEntry,
pub id_hash: H256,
pub timeout: Option<Instant>,
pub last_seen: Instant,
backoff_until: Instant,
fail_count: usize,
}
impl BucketEntry {
fn new(address: NodeEntry) -> Self {
let now = Instant::now();
BucketEntry {
id_hash: keccak(address.id),
address: address,
last_seen: now,
backoff_until: now,
fail_count: 0,
}
}
}
pub struct NodeBucket {
nodes: VecDeque<BucketEntry>, //sorted by last active
}
struct PendingRequest {
packet_id: u8,
sent_at: Instant,
packet_hash: H256,
response_count: usize, // Some requests (eg. FIND_NODE) have multi-packet responses
}
impl Default for NodeBucket {
fn default() -> Self {
NodeBucket::new()
@ -79,7 +110,7 @@ pub struct Datagram {
pub address: SocketAddr,
}
pub struct Discovery {
pub struct Discovery<'a> {
id: NodeId,
id_hash: H256,
secret: Secret,
@ -88,10 +119,14 @@ pub struct Discovery {
discovery_id: NodeId,
discovery_nodes: HashSet<NodeId>,
node_buckets: Vec<NodeBucket>,
in_flight_requests: HashMap<NodeId, PendingRequest>,
expiring_pings: VecDeque<(NodeId, Instant)>,
expiring_finds: VecDeque<(NodeId, Instant)>,
send_queue: VecDeque<Datagram>,
check_timestamps: bool,
adding_nodes: Vec<NodeEntry>,
ip_filter: IpFilter,
request_backoff: &'a [Duration],
}
pub struct TableUpdates {
@ -99,8 +134,8 @@ pub struct TableUpdates {
pub removed: HashSet<NodeId>,
}
impl Discovery {
pub fn new(key: &KeyPair, public: NodeEndpoint, ip_filter: IpFilter) -> Discovery {
impl<'a> Discovery<'a> {
pub fn new(key: &KeyPair, public: NodeEndpoint, ip_filter: IpFilter) -> Discovery<'static> {
Discovery {
id: key.public().clone(),
id_hash: keccak(key.public()),
@ -110,86 +145,80 @@ impl Discovery {
discovery_id: NodeId::new(),
discovery_nodes: HashSet::new(),
node_buckets: (0..ADDRESS_BITS).map(|_| NodeBucket::new()).collect(),
in_flight_requests: HashMap::new(),
expiring_pings: VecDeque::new(),
expiring_finds: VecDeque::new(),
send_queue: VecDeque::new(),
check_timestamps: true,
adding_nodes: Vec::new(),
ip_filter: ip_filter,
request_backoff: &REQUEST_BACKOFF,
}
}
/// Add a new node to discovery table. Pings the node.
pub fn add_node(&mut self, e: NodeEntry) {
if self.is_allowed(&e) {
let endpoint = e.endpoint.clone();
self.update_node(e);
self.ping(&endpoint);
// If distance returns None, then we are trying to add ourself.
let id_hash = keccak(e.id);
if let Some(dist) = Discovery::distance(&self.id_hash, &id_hash) {
if self.node_buckets[dist].nodes.iter().any(|n| n.id_hash == id_hash) {
return;
}
self.try_ping(e);
}
}
/// Add a list of nodes. Pings a few nodes each round
pub fn add_node_list(&mut self, nodes: Vec<NodeEntry>) {
self.adding_nodes = nodes;
self.update_new_nodes();
for node in nodes {
self.add_node(node);
}
}
/// Add a list of known nodes to the table.
pub fn init_node_list(&mut self, mut nodes: Vec<NodeEntry>) {
for n in nodes.drain(..) {
pub fn init_node_list(&mut self, nodes: Vec<NodeEntry>) {
for n in nodes {
if self.is_allowed(&n) {
self.update_node(n);
}
}
}
fn update_node(&mut self, e: NodeEntry) {
fn update_node(&mut self, e: NodeEntry) -> Option<TableUpdates> {
trace!(target: "discovery", "Inserting {:?}", &e);
let id_hash = keccak(e.id);
let dist = match Discovery::distance(&self.id_hash, &id_hash) {
Some(dist) => dist,
None => {
debug!(target: "discovery", "Attempted to update own entry: {:?}", e);
return;
return None;
}
};
let mut added_map = HashMap::new();
let ping = {
let bucket = &mut self.node_buckets[dist];
let updated = if let Some(node) = bucket.nodes.iter_mut().find(|n| n.address.id == e.id) {
node.address = e.clone();
node.timeout = None;
node.last_seen = Instant::now();
node.backoff_until = Instant::now();
node.fail_count = 0;
true
} else { false };
if !updated {
bucket.nodes.push_front(BucketEntry { address: e, timeout: None, id_hash: id_hash, });
}
added_map.insert(e.id, e.clone());
bucket.nodes.push_front(BucketEntry::new(e));
if bucket.nodes.len() > BUCKET_SIZE {
//ping least active node
let last = bucket.nodes.back_mut().expect("Last item is always present when len() > 0");
last.timeout = Some(Instant::now());
Some(last.address.endpoint.clone())
if bucket.nodes.len() > BUCKET_SIZE {
select_bucket_ping(bucket.nodes.iter())
} else { None }
} else { None }
};
if let Some(endpoint) = ping {
self.ping(&endpoint);
}
}
/// Removes the timeout of a given NodeId if it can be found in one of the discovery buckets
fn clear_ping(&mut self, id: &NodeId) {
let dist = match Discovery::distance(&self.id_hash, &keccak(id)) {
Some(dist) => dist,
None => {
debug!(target: "discovery", "Received ping from self");
return
}
};
let bucket = &mut self.node_buckets[dist];
if let Some(node) = bucket.nodes.iter_mut().find(|n| &n.address.id == id) {
node.timeout = None;
if let Some(node) = ping {
self.try_ping(node);
}
Some(TableUpdates { added: added_map, removed: HashSet::new() })
}
/// Starts the discovery process at round 0
@ -201,11 +230,11 @@ impl Discovery {
}
fn update_new_nodes(&mut self) {
let mut count = 0usize;
while !self.adding_nodes.is_empty() && count < MAX_NODES_PING {
let node = self.adding_nodes.pop().expect("pop is always Some if not empty; qed");
self.add_node(node);
count += 1;
while self.in_flight_requests.len() < MAX_NODES_PING {
match self.adding_nodes.pop() {
Some(next) => self.try_ping(next),
None => break,
}
}
}
@ -219,13 +248,17 @@ impl Discovery {
{
let nearest = self.nearest_node_entries(&self.discovery_id).into_iter();
let nearest = nearest.filter(|x| !self.discovery_nodes.contains(&x.id)).take(ALPHA).collect::<Vec<_>>();
let target = self.discovery_id.clone();
for r in nearest {
let rlp = encode_list(&(&[self.discovery_id.clone()][..]));
self.send_packet(PACKET_FIND_NODE, &r.endpoint.udp_address(), &rlp)
.unwrap_or_else(|e| warn!("Error sending node discovery packet for {:?}: {:?}", &r.endpoint, e));
self.discovery_nodes.insert(r.id.clone());
tried_count += 1;
trace!(target: "discovery", "Sent FindNode to {:?}", &r.endpoint);
match self.send_find_node(&r, &target) {
Ok(()) => {
self.discovery_nodes.insert(r.id.clone());
tried_count += 1;
},
Err(e) => {
warn!(target: "discovery", "Error sending node discovery packet for {:?}: {:?}", &r.endpoint, e);
},
};
}
}
@ -251,46 +284,71 @@ impl Discovery {
None // a and b are equal, so log distance is -inf
}
fn ping(&mut self, node: &NodeEndpoint) {
let mut rlp = RlpStream::new_list(3);
rlp.append(&PROTOCOL_VERSION);
self.public_endpoint.to_rlp_list(&mut rlp);
node.to_rlp_list(&mut rlp);
trace!(target: "discovery", "Sent Ping to {:?}", &node);
self.send_packet(PACKET_PING, &node.udp_address(), &rlp.drain())
.unwrap_or_else(|e| warn!("Error sending Ping packet: {:?}", e))
fn try_ping(&mut self, node: NodeEntry) {
if !self.is_allowed(&node) ||
self.in_flight_requests.contains_key(&node.id) ||
self.adding_nodes.iter().any(|n| n.id == node.id)
{
return;
}
if self.in_flight_requests.len() < MAX_NODES_PING {
self.ping(&node)
.unwrap_or_else(|e| {
warn!(target: "discovery", "Error sending Ping packet: {:?}", e);
});
} else {
self.adding_nodes.push(node);
}
}
fn send_packet(&mut self, packet_id: u8, address: &SocketAddr, payload: &[u8]) -> Result<(), Error> {
let mut rlp = RlpStream::new();
rlp.append_raw(&[packet_id], 1);
let source = Rlp::new(payload);
rlp.begin_list(source.item_count()? + 1);
for i in 0 .. source.item_count()? {
rlp.append_raw(source.at(i)?.as_raw(), 1);
}
let timestamp = 60 + SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_secs() as u32;
rlp.append(&timestamp);
fn ping(&mut self, node: &NodeEntry) -> Result<(), Error> {
let mut rlp = RlpStream::new_list(4);
rlp.append(&PROTOCOL_VERSION);
self.public_endpoint.to_rlp_list(&mut rlp);
node.endpoint.to_rlp_list(&mut rlp);
append_expiration(&mut rlp);
let hash = self.send_packet(PACKET_PING, &node.endpoint.udp_address(), &rlp.drain())?;
let bytes = rlp.drain();
let hash = keccak(bytes.as_ref());
let signature = match sign(&self.secret, &hash) {
Ok(s) => s,
Err(e) => {
warn!("Error signing UDP packet");
return Err(Error::from(e));
}
let request_info = PendingRequest {
packet_id: PACKET_PING,
sent_at: Instant::now(),
packet_hash: hash,
response_count: 0,
};
let mut packet = Bytes::with_capacity(bytes.len() + 32 + 65);
packet.extend(hash.iter());
packet.extend(signature.iter());
packet.extend(bytes.iter());
let signed_hash = keccak(&packet[32..]);
packet[0..32].clone_from_slice(&signed_hash);
self.send_to(packet, address.clone());
self.expiring_pings.push_back((node.id, request_info.sent_at));
self.in_flight_requests.insert(node.id, request_info);
trace!(target: "discovery", "Sent Ping to {:?}", &node.endpoint);
Ok(())
}
fn send_find_node(&mut self, node: &NodeEntry, target: &NodeId) -> Result<(), Error> {
let mut rlp = RlpStream::new_list(2);
rlp.append(target);
append_expiration(&mut rlp);
let hash = self.send_packet(PACKET_FIND_NODE, &node.endpoint.udp_address(), &rlp.drain())?;
let request_info = PendingRequest {
packet_id: PACKET_FIND_NODE,
sent_at: Instant::now(),
packet_hash: hash,
response_count: 0,
};
self.expiring_finds.push_back((node.id, request_info.sent_at));
self.in_flight_requests.insert(node.id, request_info);
trace!(target: "discovery", "Sent FindNode to {:?}", &node.endpoint);
Ok(())
}
fn send_packet(&mut self, packet_id: u8, address: &SocketAddr, payload: &[u8]) -> Result<H256, Error> {
let packet = assemble_packet(packet_id, payload, &self.secret)?;
let hash = H256::from(&packet[0..32]);
self.send_to(packet, address.clone());
Ok(hash)
}
fn nearest_node_entries(&self, target: &NodeId) -> Vec<NodeEntry> {
let target_hash = keccak(target);
let target_distance = self.id_hash ^ target_hash;
@ -396,37 +454,57 @@ impl Discovery {
let dest = NodeEndpoint::from_rlp(&rlp.at(2)?)?;
let timestamp: u64 = rlp.val_at(3)?;
self.check_timestamp(timestamp)?;
let mut added_map = HashMap::new();
let mut response = RlpStream::new_list(3);
dest.to_rlp_list(&mut response);
response.append(&echo_hash);
append_expiration(&mut response);
self.send_packet(PACKET_PONG, from, &response.drain())?;
let entry = NodeEntry { id: node.clone(), endpoint: source.clone() };
if !entry.endpoint.is_valid() {
debug!(target: "discovery", "Got bad address: {:?}", entry);
} else if !self.is_allowed(&entry) {
debug!(target: "discovery", "Address not allowed: {:?}", entry);
} else {
self.update_node(entry.clone());
added_map.insert(node.clone(), entry);
self.add_node(entry.clone());
}
let mut response = RlpStream::new_list(2);
dest.to_rlp_list(&mut response);
response.append(&echo_hash);
self.send_packet(PACKET_PONG, from, &response.drain())?;
Ok(Some(TableUpdates { added: added_map, removed: HashSet::new() }))
Ok(None)
}
fn on_pong(&mut self, rlp: &Rlp, node: &NodeId, from: &SocketAddr) -> Result<Option<TableUpdates>, Error> {
fn on_pong(&mut self, rlp: &Rlp, node_id: &NodeId, from: &SocketAddr) -> Result<Option<TableUpdates>, Error> {
trace!(target: "discovery", "Got Pong from {:?}", &from);
// TODO: validate pong packet in rlp.val_at(1)
let dest = NodeEndpoint::from_rlp(&rlp.at(0)?)?;
let echo_hash: H256 = rlp.val_at(1)?;
let timestamp: u64 = rlp.val_at(2)?;
self.check_timestamp(timestamp)?;
let mut entry = NodeEntry { id: node.clone(), endpoint: dest };
if !entry.endpoint.is_valid() {
debug!(target: "discovery", "Bad address: {:?}", entry);
entry.endpoint.address = from.clone();
let mut node = NodeEntry { id: node_id.clone(), endpoint: dest };
if !node.endpoint.is_valid() {
debug!(target: "discovery", "Bad address: {:?}", node);
node.endpoint.address = from.clone();
}
let is_expected = match self.in_flight_requests.entry(*node_id) {
Entry::Occupied(entry) => {
let is_expected = {
let request = entry.get();
request.packet_id == PACKET_PING && request.packet_hash == echo_hash
};
if is_expected {
entry.remove();
}
is_expected
},
Entry::Vacant(_) => false
};
if is_expected {
Ok(self.update_node(node))
} else {
debug!(target: "discovery", "Got unexpected Pong from {:?}", &from);
Ok(None)
}
self.clear_ping(node);
Ok(None)
}
fn on_find_node(&mut self, rlp: &Rlp, _node: &NodeId, from: &SocketAddr) -> Result<Option<TableUpdates>, Error> {
@ -450,22 +528,49 @@ impl Discovery {
let limit = (MAX_DATAGRAM_SIZE - 109) / 90;
let chunks = nearest.chunks(limit);
let packets = chunks.map(|c| {
let mut rlp = RlpStream::new_list(1);
let mut rlp = RlpStream::new_list(2);
rlp.begin_list(c.len());
for n in 0 .. c.len() {
rlp.begin_list(4);
c[n].endpoint.to_rlp(&mut rlp);
rlp.append(&c[n].id);
}
append_expiration(&mut rlp);
rlp.out()
});
packets.collect()
}
fn on_neighbours(&mut self, rlp: &Rlp, _node: &NodeId, from: &SocketAddr) -> Result<Option<TableUpdates>, Error> {
// TODO: validate packet
let mut added = HashMap::new();
trace!(target: "discovery", "Got {} Neighbours from {:?}", rlp.at(0)?.item_count()?, &from);
fn on_neighbours(&mut self, rlp: &Rlp, node_id: &NodeId, from: &SocketAddr) -> Result<Option<TableUpdates>, Error> {
let results_count = rlp.at(0)?.item_count()?;
let is_expected = match self.in_flight_requests.entry(*node_id) {
Entry::Occupied(mut entry) => {
let result = {
let request = entry.get_mut();
if request.packet_id == PACKET_FIND_NODE &&
request.response_count + results_count <= BUCKET_SIZE
{
request.response_count += results_count;
true
} else {
false
}
};
if entry.get().response_count == BUCKET_SIZE {
entry.remove();
}
result
}
Entry::Vacant(_) => false,
};
if !is_expected {
debug!(target: "discovery", "Got unexpected Neighbors from {:?}", &from);
return Ok(None);
}
trace!(target: "discovery", "Got {} Neighbours from {:?}", results_count, &from);
for r in rlp.at(0)?.iter() {
let endpoint = NodeEndpoint::from_rlp(&r)?;
if !endpoint.is_valid() {
@ -481,35 +586,62 @@ impl Discovery {
debug!(target: "discovery", "Address not allowed: {:?}", entry);
continue;
}
added.insert(node_id, entry.clone());
self.ping(&entry.endpoint);
self.update_node(entry);
self.add_node(entry);
}
Ok(Some(TableUpdates { added: added, removed: HashSet::new() }))
Ok(None)
}
fn check_expired(&mut self, force: bool) -> HashSet<NodeId> {
let now = Instant::now();
fn check_expired(&mut self, time: Instant) -> HashSet<NodeId> {
let mut removed: HashSet<NodeId> = HashSet::new();
for bucket in &mut self.node_buckets {
bucket.nodes.retain(|node| {
if let Some(timeout) = node.timeout {
if !force && now.duration_since(timeout) < PING_TIMEOUT {
true
}
else {
trace!(target: "discovery", "Removed expired node {:?}", &node.address);
removed.insert(node.address.id.clone());
false
}
} else { true }
});
while let Some((node_id, sent_at)) = self.expiring_pings.pop_front() {
if time.duration_since(sent_at) <= PING_TIMEOUT {
self.expiring_pings.push_front((node_id, sent_at));
break;
}
self.expire_in_flight_request(node_id, sent_at, &mut removed);
}
while let Some((node_id, sent_at)) = self.expiring_finds.pop_front() {
if time.duration_since(sent_at) <= FIND_NODE_TIMEOUT {
self.expiring_finds.push_front((node_id, sent_at));
break;
}
self.expire_in_flight_request(node_id, sent_at, &mut removed);
}
removed
}
fn expire_in_flight_request(&mut self, node_id: NodeId, sent_at: Instant, removed: &mut HashSet<NodeId>) {
if let Entry::Occupied(entry) = self.in_flight_requests.entry(node_id) {
if entry.get().sent_at == sent_at {
entry.remove();
// Attempt to remove from bucket if in one.
let id_hash = keccak(&node_id);
let dist = Discovery::distance(&self.id_hash, &id_hash)
.expect("distance is None only if id hashes are equal; will never send request to self; qed");
let bucket = &mut self.node_buckets[dist];
if let Some(index) = bucket.nodes.iter().position(|n| n.id_hash == id_hash) {
if bucket.nodes[index].fail_count < self.request_backoff.len() {
let node = &mut bucket.nodes[index];
node.backoff_until = Instant::now() + self.request_backoff[node.fail_count];
node.fail_count += 1;
trace!(
target: "discovery",
"Requests to node {:?} timed out {} consecutive time(s)",
&node.address, node.fail_count
);
} else {
removed.insert(node_id);
let node = bucket.nodes.remove(index).expect("index was located in if condition");
debug!(target: "discovery", "Removed expired node {:?}", &node.address);
}
}
}
}
}
pub fn round(&mut self) -> Option<TableUpdates> {
let removed = self.check_expired(false);
let removed = self.check_expired(Instant::now());
self.discover();
if !removed.is_empty() {
Some(TableUpdates { added: HashMap::new(), removed: removed })
@ -533,10 +665,48 @@ impl Discovery {
}
}
fn append_expiration(rlp: &mut RlpStream) {
let expiry = SystemTime::now() + EXPIRY_TIME;
let timestamp = expiry.duration_since(UNIX_EPOCH).unwrap_or_default().as_secs() as u32;
rlp.append(&timestamp);
}
fn assemble_packet(packet_id: u8, bytes: &[u8], secret: &Secret) -> Result<Bytes, Error> {
let mut packet = Bytes::with_capacity(bytes.len() + 32 + 65 + 1);
packet.resize(32 + 65, 0); // Filled in below
packet.push(packet_id);
packet.extend_from_slice(bytes);
let hash = keccak(&packet[(32 + 65)..]);
let signature = match sign(secret, &hash) {
Ok(s) => s,
Err(e) => {
warn!(target: "discovery", "Error signing UDP packet");
return Err(Error::from(e));
}
};
packet[32..(32 + 65)].copy_from_slice(&signature[..]);
let signed_hash = keccak(&packet[32..]);
packet[0..32].copy_from_slice(&signed_hash);
Ok(packet)
}
// Selects the next node in a bucket to ping. Chooses the eligible node least recently seen.
fn select_bucket_ping<'a, I>(nodes: I) -> Option<NodeEntry>
where
I: Iterator<Item=&'a BucketEntry>
{
let now = Instant::now();
nodes
.filter(|n| n.backoff_until < now)
.min_by_key(|n| n.last_seen)
.map(|n| n.address.clone())
}
#[cfg(test)]
mod tests {
use super::*;
use std::net::{SocketAddr};
use std::net::{IpAddr,Ipv4Addr};
use node_table::{Node, NodeId, NodeEndpoint};
use std::str::FromStr;
@ -561,49 +731,150 @@ mod tests {
}
#[test]
fn discovery() {
let key1 = Random.generate().unwrap();
let key2 = Random.generate().unwrap();
let ep1 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40444").unwrap(), udp_port: 40444 };
let ep2 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40445").unwrap(), udp_port: 40445 };
let mut discovery1 = Discovery::new(&key1, ep1.clone(), IpFilter::default());
let mut discovery2 = Discovery::new(&key2, ep2.clone(), IpFilter::default());
fn ping_queue() {
let key = Random.generate().unwrap();
let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40445").unwrap(), udp_port: 40445 };
let mut discovery = Discovery::new(&key, ep.clone(), IpFilter::default());
let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7770").unwrap();
let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7771").unwrap();
discovery1.add_node(NodeEntry { id: node1.id.clone(), endpoint: node1.endpoint.clone() });
discovery1.add_node(NodeEntry { id: node2.id.clone(), endpoint: node2.endpoint.clone() });
discovery2.add_node(NodeEntry { id: key1.public().clone(), endpoint: ep1.clone() });
discovery2.refresh();
for _ in 0 .. 10 {
while let Some(datagram) = discovery1.dequeue_send() {
if datagram.address == ep2.address {
discovery2.on_packet(&datagram.payload, ep1.address.clone()).ok();
}
}
while let Some(datagram) = discovery2.dequeue_send() {
if datagram.address == ep1.address {
discovery1.on_packet(&datagram.payload, ep2.address.clone()).ok();
}
}
discovery2.round();
for i in 1..(MAX_NODES_PING+1) {
discovery.add_node(NodeEntry { id: NodeId::random(), endpoint: ep.clone() });
assert_eq!(discovery.in_flight_requests.len(), i);
assert_eq!(discovery.send_queue.len(), i);
assert_eq!(discovery.adding_nodes.len(), 0);
}
assert_eq!(discovery2.nearest_node_entries(&NodeId::new()).len(), 3)
for i in 1..20 {
discovery.add_node(NodeEntry { id: NodeId::random(), endpoint: ep.clone() });
assert_eq!(discovery.in_flight_requests.len(), MAX_NODES_PING);
assert_eq!(discovery.send_queue.len(), MAX_NODES_PING);
assert_eq!(discovery.adding_nodes.len(), i);
}
}
#[test]
fn discovery() {
let mut discovery_handlers = (0..5).map(|i| {
let key = Random.generate().unwrap();
let ep = NodeEndpoint {
address: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 41000 + i),
udp_port: 41000 + i,
};
Discovery::new(&key, ep, IpFilter::default())
})
.collect::<Vec<_>>();
// Sort inversely by XOR distance to the 0 hash.
discovery_handlers.sort_by(|a, b| b.id_hash.cmp(&a.id_hash));
// Initialize the routing table of each with the next one in order.
for i in 0 .. 5 {
let node = NodeEntry {
id: discovery_handlers[(i + 1) % 5].id,
endpoint: discovery_handlers[(i + 1) % 5].public_endpoint.clone(),
};
discovery_handlers[i].update_node(node);
}
// After 4 discovery rounds, the first one should have learned about the rest.
for _round in 0 .. 4 {
discovery_handlers[0].round();
let mut continue_loop = true;
while continue_loop {
continue_loop = false;
// Process all queued messages.
for i in 0 .. 5 {
let src = discovery_handlers[i].public_endpoint.address.clone();
while let Some(datagram) = discovery_handlers[i].dequeue_send() {
let dest = discovery_handlers.iter_mut()
.find(|disc| datagram.address == disc.public_endpoint.address)
.unwrap();
dest.on_packet(&datagram.payload, src).ok();
continue_loop = true;
}
}
}
}
let results = discovery_handlers[0].nearest_node_entries(&NodeId::new());
assert_eq!(results.len(), 4);
}
#[test]
fn removes_expired() {
let key = Random.generate().unwrap();
let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40446").unwrap(), udp_port: 40447 };
let mut discovery = Discovery::new(&key, ep.clone(), IpFilter::default());
for _ in 0..1200 {
let discovery = Discovery::new(&key, ep.clone(), IpFilter::default());
let mut discovery = Discovery { request_backoff: &[], ..discovery };
let total_bucket_nodes = |node_buckets: &Vec<NodeBucket>| -> usize {
node_buckets.iter().map(|bucket| bucket.nodes.len()).sum()
};
let node_entries = (0..1200)
.map(|_| NodeEntry { id: NodeId::random(), endpoint: ep.clone() })
.collect::<Vec<_>>();
discovery.init_node_list(node_entries.clone());
assert_eq!(total_bucket_nodes(&discovery.node_buckets), 1200);
// Requests have not expired yet.
let removed = discovery.check_expired(Instant::now()).len();
assert_eq!(removed, 0);
// Expiring pings to bucket nodes removes them from bucket.
let removed = discovery.check_expired(Instant::now() + PING_TIMEOUT).len();
assert!(removed > 0);
assert_eq!(total_bucket_nodes(&discovery.node_buckets), 1200 - removed);
for _ in 0..100 {
discovery.add_node(NodeEntry { id: NodeId::random(), endpoint: ep.clone() });
}
assert!(discovery.nearest_node_entries(&NodeId::new()).len() <= 16);
let removed = discovery.check_expired(true).len();
assert!(discovery.in_flight_requests.len() > 0);
// Expire pings to nodes that are not in buckets.
let removed = discovery.check_expired(Instant::now() + PING_TIMEOUT).len();
assert_eq!(removed, 0);
assert_eq!(discovery.in_flight_requests.len(), 0);
let from = SocketAddr::from_str("99.99.99.99:40445").unwrap();
// FIND_NODE times out because it doesn't receive k results.
let key = Random.generate().unwrap();
discovery.send_find_node(&node_entries[100], key.public()).unwrap();
for payload in Discovery::prepare_neighbours_packets(&node_entries[101..116]) {
let packet = assemble_packet(PACKET_NEIGHBOURS, &payload, &key.secret()).unwrap();
discovery.on_packet(&packet, from.clone()).unwrap();
}
let removed = discovery.check_expired(Instant::now() + FIND_NODE_TIMEOUT).len();
assert!(removed > 0);
// FIND_NODE does not time out because it receives k results.
discovery.send_find_node(&node_entries[100], key.public()).unwrap();
for payload in Discovery::prepare_neighbours_packets(&node_entries[101..117]) {
let packet = assemble_packet(PACKET_NEIGHBOURS, &payload, &key.secret()).unwrap();
discovery.on_packet(&packet, from.clone()).unwrap();
}
let removed = discovery.check_expired(Instant::now() + FIND_NODE_TIMEOUT).len();
assert_eq!(removed, 0);
// Test bucket evictions with retries.
let request_backoff = [Duration::new(0, 0); 2];
let mut discovery = Discovery { request_backoff: &request_backoff, ..discovery };
for _ in 0..2 {
discovery.ping(&node_entries[101]).unwrap();
let removed = discovery.check_expired(Instant::now() + PING_TIMEOUT).len();
assert_eq!(removed, 0);
}
discovery.ping(&node_entries[101]).unwrap();
let removed = discovery.check_expired(Instant::now() + PING_TIMEOUT).len();
assert_eq!(removed, 1);
}
#[test]
@ -615,11 +886,8 @@ mod tests {
let mut discovery = Discovery::new(&key, ep.clone(), IpFilter::default());
for _ in 0..(16 + 10) {
discovery.node_buckets[0].nodes.push_back(BucketEntry {
address: NodeEntry { id: NodeId::new(), endpoint: ep.clone() },
timeout: None,
id_hash: keccak(NodeId::new()),
});
let entry = BucketEntry::new(NodeEntry { id: NodeId::new(), endpoint: ep.clone() });
discovery.node_buckets[0].nodes.push_back(entry);
}
let nearest = discovery.nearest_node_entries(&NodeId::new());
assert_eq!(nearest.len(), 16)
@ -674,7 +942,7 @@ mod tests {
.unwrap();
let mut discovery = Discovery::new(&key, ep.clone(), IpFilter::default());
node_entries.iter().for_each(|entry| discovery.update_node(entry.clone()));
discovery.init_node_list(node_entries.clone());
let expected_bucket_sizes = vec![
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@ -782,17 +1050,70 @@ mod tests {
fn test_ping() {
let key1 = Random.generate().unwrap();
let key2 = Random.generate().unwrap();
let key3 = Random.generate().unwrap();
let ep1 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40344").unwrap(), udp_port: 40344 };
let ep2 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40345").unwrap(), udp_port: 40345 };
let ep3 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40346").unwrap(), udp_port: 40345 };
let mut discovery1 = Discovery::new(&key1, ep1.clone(), IpFilter::default());
let mut discovery2 = Discovery::new(&key2, ep2.clone(), IpFilter::default());
discovery1.ping(&ep2);
discovery1.ping(&NodeEntry { id: discovery2.id, endpoint: ep2.clone() }).unwrap();
let ping_data = discovery1.dequeue_send().unwrap();
discovery2.on_packet(&ping_data.payload, ep1.address.clone()).ok();
assert!(!discovery1.any_sends_queued());
let data = &ping_data.payload[(32 + 65)..];
assert_eq!(data[0], PACKET_PING);
let rlp = Rlp::new(&data[1..]);
assert_eq!(ep1, NodeEndpoint::from_rlp(&rlp.at(1).unwrap()).unwrap());
assert_eq!(ep2, NodeEndpoint::from_rlp(&rlp.at(2).unwrap()).unwrap());
if let Some(_) = discovery2.on_packet(&ping_data.payload, ep1.address.clone()).unwrap() {
panic!("Expected no changes to discovery2's table");
}
let pong_data = discovery2.dequeue_send().unwrap();
let data = &pong_data.payload[(32 + 65)..];
assert_eq!(data[0], PACKET_PONG);
let rlp = Rlp::new(&data[1..]);
assert_eq!(ping_data.payload[0..32], rlp.val_at::<Vec<u8>>(1).unwrap()[..])
assert_eq!(ping_data.payload[0..32], rlp.val_at::<Vec<u8>>(1).unwrap()[..]);
// Create a pong packet with incorrect echo hash and assert that it is rejected.
let mut incorrect_pong_rlp = RlpStream::new_list(3);
ep1.to_rlp_list(&mut incorrect_pong_rlp);
incorrect_pong_rlp.append(&H256::default());
append_expiration(&mut incorrect_pong_rlp);
let incorrect_pong_data = assemble_packet(
PACKET_PONG, &incorrect_pong_rlp.drain(), &discovery2.secret
).unwrap();
if let Some(_) = discovery1.on_packet(&incorrect_pong_data, ep2.address.clone()).unwrap() {
panic!("Expected no changes to discovery1's table because pong hash is incorrect");
}
// Delivery of valid pong response should add to routing table.
if let Some(table_updates) = discovery1.on_packet(&pong_data.payload, ep2.address.clone()).unwrap() {
assert_eq!(table_updates.added.len(), 1);
assert_eq!(table_updates.removed.len(), 0);
assert!(table_updates.added.contains_key(&discovery2.id));
} else {
panic!("Expected discovery1 to be added to discovery1's table");
}
let ping_back = discovery2.dequeue_send().unwrap();
assert!(!discovery2.any_sends_queued());
let data = &ping_back.payload[(32 + 65)..];
assert_eq!(data[0], PACKET_PING);
let rlp = Rlp::new(&data[1..]);
assert_eq!(ep2, NodeEndpoint::from_rlp(&rlp.at(1).unwrap()).unwrap());
assert_eq!(ep1, NodeEndpoint::from_rlp(&rlp.at(2).unwrap()).unwrap());
// Deliver an unexpected PONG message to discover1.
let mut unexpected_pong_rlp = RlpStream::new_list(3);
ep3.to_rlp_list(&mut unexpected_pong_rlp);
unexpected_pong_rlp.append(&H256::default());
append_expiration(&mut unexpected_pong_rlp);
let unexpected_pong = assemble_packet(
PACKET_PONG, &unexpected_pong_rlp.drain(), key3.secret()
).unwrap();
if let Some(_) = discovery1.on_packet(&unexpected_pong, ep3.address.clone()).unwrap() {
panic!("Expected no changes to discovery1's table for unexpected pong");
}
}
}

View File

@ -243,7 +243,7 @@ pub struct Host {
udp_socket: Mutex<Option<UdpSocket>>,
tcp_listener: Mutex<TcpListener>,
sessions: Arc<RwLock<Slab<SharedSession>>>,
discovery: Mutex<Option<Discovery>>,
discovery: Mutex<Option<Discovery<'static>>>,
nodes: RwLock<NodeTable>,
handlers: RwLock<HashMap<ProtocolId, Arc<NetworkProtocolHandler + Sync>>>,
timers: RwLock<HashMap<TimerToken, ProtocolTimer>>,

View File

@ -33,7 +33,7 @@ use rand::{self, Rng};
/// Node public key
pub type NodeId = H512;
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
/// Node address info
pub struct NodeEndpoint {
/// IP(V4 or V6) address

View File

@ -10,7 +10,7 @@ build = "build.rs"
[package.metadata]
# This versions track. Should be changed to `stable` or `beta` when on respective branches.
# Used by auto-updater and for Parity version string.
track = "nightly"
track = "beta"
# Network specific settings, used ONLY by auto-updater.
# Latest supported fork blocks.