Compare commits
113 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
2ce7144835 | ||
|
fa14a62c8d | ||
|
7f5795dee6 | ||
|
d0b6f2648b | ||
|
a79cf7155a | ||
|
5baccf6f65 | ||
|
95ee6300df | ||
|
dc19465d31 | ||
|
dc8bc8d8dd | ||
|
3102cf7bc6 | ||
|
ada9b02141 | ||
|
f5d14e01d4 | ||
|
bb9ff46a32 | ||
|
1c177adca1 | ||
|
c585985543 | ||
|
1be865beb0 | ||
|
260bcfd368 | ||
|
02be8d869c | ||
|
46ac2cb94b | ||
|
659cf2bb37 | ||
|
d3d6ff8ca9 | ||
|
74b850e7fc | ||
|
e4e25b771e | ||
|
7fc3f4eda0 | ||
|
b20ffbde8e | ||
|
3fe38163f5 | ||
|
0d18436a3d | ||
|
9ebfb14bb5 | ||
|
82e33fa033 | ||
|
fa8eb22e79 | ||
|
55b51890dd | ||
|
0f99b1e123 | ||
|
51e4c82337 | ||
|
7df702494d | ||
|
b5219bc723 | ||
|
27765a71dd | ||
|
a1b9f03121 | ||
|
1c40421982 | ||
|
07324795f1 | ||
|
19520442c1 | ||
|
e0c5baece0 | ||
|
f4f7b83d1f | ||
|
30d7872226 | ||
|
4d4821c577 | ||
|
948a5387b3 | ||
|
8a050e4464 | ||
|
af998d8c40 | ||
|
591673821c | ||
|
ce5dfd8e34 | ||
|
8c049e5d05 | ||
|
2bfcfd3813 | ||
|
4f869a9ba5 | ||
|
dd0b2c2327 | ||
|
889f85ea0d | ||
|
42eec0f6bd | ||
|
449e85743d | ||
|
8764563222 | ||
|
5b31af4e09 | ||
|
b648bd403a | ||
|
0994b91af5 | ||
|
2e595d60f0 | ||
|
c2ceefbc22 | ||
|
ab2d02bbb6 | ||
|
43bb862adb | ||
|
172b40ae30 | ||
|
74e859a9d4 | ||
|
1fdbc07cb4 | ||
|
9912a3158c | ||
|
fa6aceca42 | ||
|
503137a968 | ||
|
184648a734 | ||
|
fb817fcdca | ||
|
f76b94c2c5 | ||
|
78afa8ed54 | ||
|
63bf2755ed | ||
|
f187b15a43 | ||
|
e9b1921950 | ||
|
3106835ae3 | ||
|
c7dbd87f8e | ||
|
b09cfe1885 | ||
|
070c40c02f | ||
|
33ecf1313f | ||
|
971a481b0d | ||
|
2b132c38d6 | ||
|
dcd9119452 | ||
|
f3f25ad50c | ||
|
f3c4ea4fb9 | ||
|
1b79fc3e27 | ||
|
ce824089ac | ||
|
d2e6fc0a65 | ||
|
29d50f8f30 | ||
|
536cf73db8 | ||
|
f15a3ca977 | ||
|
096a44d9bf | ||
|
ff3ae33d99 | ||
|
8e6d09e6ac | ||
|
516e16a36b | ||
|
77b14b2736 | ||
|
e01636fc34 | ||
|
7b2cfd1cfb | ||
|
cf6d870b09 | ||
|
f20db41169 | ||
|
6830273cb9 | ||
|
65594b8865 | ||
|
5b30a61158 | ||
|
0bc2aeca8d | ||
|
1478109c43 | ||
|
bbd2bd0e17 | ||
|
1e212771b5 | ||
|
72bb687f5e | ||
|
5e70507c78 | ||
|
2b588d57f0 | ||
|
e7fbf10819 |
122
.gitlab-ci.yml
122
.gitlab-ci.yml
@ -38,7 +38,7 @@ linux-stable:
|
|||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/parity.md5 --body parity.md5
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/parity.md5 --body parity.md5
|
||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/"parity_"$VER"_amd64.deb" --body "parity_"$VER"_amd64.deb"
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/"parity_"$VER"_amd64.deb" --body "parity_"$VER"_amd64.deb"
|
||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/"parity_"$VER"_amd64.deb.md5" --body "parity_"$VER"_amd64.deb.md5"
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/"parity_"$VER"_amd64.deb.md5" --body "parity_"$VER"_amd64.deb.md5"
|
||||||
# - curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1337/push-build/$CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu
|
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1337/push-build/$CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu
|
||||||
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1338/push-build/$CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu
|
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1338/push-build/$CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu
|
||||||
tags:
|
tags:
|
||||||
- rust
|
- rust
|
||||||
@ -47,6 +47,41 @@ linux-stable:
|
|||||||
paths:
|
paths:
|
||||||
- target/release/parity
|
- target/release/parity
|
||||||
name: "stable-x86_64-unknown-linux-gnu_parity"
|
name: "stable-x86_64-unknown-linux-gnu_parity"
|
||||||
|
linux-stable-debian:
|
||||||
|
stage: build
|
||||||
|
image: ethcore/rust-debian:latest
|
||||||
|
only:
|
||||||
|
- beta
|
||||||
|
- tags
|
||||||
|
- stable
|
||||||
|
- triggers
|
||||||
|
script:
|
||||||
|
- cargo build -j $(nproc) --release --features final $CARGOFLAGS
|
||||||
|
- strip target/release/parity
|
||||||
|
- export SHA3=$(target/release/parity tools hash target/release/parity)
|
||||||
|
- md5sum target/release/parity > parity.md5
|
||||||
|
- sh scripts/deb-build.sh amd64
|
||||||
|
- cp target/release/parity deb/usr/bin/parity
|
||||||
|
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
|
||||||
|
- dpkg-deb -b deb "parity_"$VER"_amd64.deb"
|
||||||
|
- md5sum "parity_"$VER"_amd64.deb" > "parity_"$VER"_amd64.deb.md5"
|
||||||
|
- aws configure set aws_access_key_id $s3_key
|
||||||
|
- aws configure set aws_secret_access_key $s3_secret
|
||||||
|
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable)$ ]]; then export S3_BUCKET=builds-parity-published; else export S3_BUCKET=builds-parity; fi
|
||||||
|
- aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/x86_64-unknown-debian-gnu
|
||||||
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-debian-gnu/parity --body target/release/parity
|
||||||
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-debian-gnu/parity.md5 --body parity.md5
|
||||||
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-debian-gnu/"parity_"$VER"_amd64.deb" --body "parity_"$VER"_amd64.deb"
|
||||||
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-debian-gnu/"parity_"$VER"_amd64.deb.md5" --body "parity_"$VER"_amd64.deb.md5"
|
||||||
|
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1337/push-build/$CI_BUILD_REF_NAME/x86_64-unknown-debian-gnu
|
||||||
|
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1338/push-build/$CI_BUILD_REF_NAME/x86_64-unknown-debian-gnu
|
||||||
|
tags:
|
||||||
|
- rust
|
||||||
|
- rust-debian
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- target/release/parity
|
||||||
|
name: "stable-x86_64-unknown-debian-gnu_parity"
|
||||||
linux-beta:
|
linux-beta:
|
||||||
stage: build
|
stage: build
|
||||||
image: ethcore/rust:beta
|
image: ethcore/rust:beta
|
||||||
@ -107,7 +142,7 @@ linux-centos:
|
|||||||
- aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu
|
- aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu
|
||||||
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/parity --body target/release/parity
|
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/parity --body target/release/parity
|
||||||
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/parity.md5 --body parity.md5
|
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/parity.md5 --body parity.md5
|
||||||
# - curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
||||||
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1338/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1338/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
||||||
tags:
|
tags:
|
||||||
- rust
|
- rust
|
||||||
@ -146,7 +181,7 @@ linux-i686:
|
|||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity.md5 --body parity.md5
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity.md5 --body parity.md5
|
||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_i386.deb" --body "parity_"$VER"_i386.deb"
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_i386.deb" --body "parity_"$VER"_i386.deb"
|
||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_i386.deb.md5" --body "parity_"$VER"_i386.deb.md5"
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_i386.deb.md5" --body "parity_"$VER"_i386.deb.md5"
|
||||||
# - curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
||||||
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1338/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1338/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
||||||
tags:
|
tags:
|
||||||
- rust
|
- rust
|
||||||
@ -192,7 +227,7 @@ linux-armv7:
|
|||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity.md5 --body parity.md5
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity.md5 --body parity.md5
|
||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_armhf.deb" --body "parity_"$VER"_armhf.deb"
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_armhf.deb" --body "parity_"$VER"_armhf.deb"
|
||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_armhf.deb.md5" --body "parity_"$VER"_armhf.deb.md5"
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_armhf.deb.md5" --body "parity_"$VER"_armhf.deb.md5"
|
||||||
# - curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
||||||
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1338/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1338/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
||||||
tags:
|
tags:
|
||||||
- rust
|
- rust
|
||||||
@ -238,7 +273,7 @@ linux-arm:
|
|||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity.md5 --body parity.md5
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity.md5 --body parity.md5
|
||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_armhf.deb" --body "parity_"$VER"_armhf.deb"
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_armhf.deb" --body "parity_"$VER"_armhf.deb"
|
||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_armhf.deb.md5" --body "parity_"$VER"_armhf.deb.md5"
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_armhf.deb.md5" --body "parity_"$VER"_armhf.deb.md5"
|
||||||
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://icarus.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
||||||
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1338/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1338/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
||||||
tags:
|
tags:
|
||||||
- rust
|
- rust
|
||||||
@ -252,10 +287,10 @@ linux-armv6:
|
|||||||
stage: build
|
stage: build
|
||||||
image: ethcore/rust-armv6:latest
|
image: ethcore/rust-armv6:latest
|
||||||
only:
|
only:
|
||||||
- beta
|
# - beta
|
||||||
# - tags
|
# - tags
|
||||||
# - stable
|
# - stable
|
||||||
# - triggers
|
- triggers
|
||||||
script:
|
script:
|
||||||
- export CC=arm-linux-gnueabi-gcc
|
- export CC=arm-linux-gnueabi-gcc
|
||||||
- export CXX=arm-linux-gnueabi-g++
|
- export CXX=arm-linux-gnueabi-g++
|
||||||
@ -277,7 +312,7 @@ linux-armv6:
|
|||||||
- aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/$PLATFORM
|
- aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/$PLATFORM
|
||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity --body target/$PLATFORM/release/parity
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity --body target/$PLATFORM/release/parity
|
||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity.md5 --body parity.md5
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity.md5 --body parity.md5
|
||||||
# - curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
||||||
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1338/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1338/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
||||||
tags:
|
tags:
|
||||||
- rust
|
- rust
|
||||||
@ -322,7 +357,7 @@ linux-aarch64:
|
|||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity.md5 --body parity.md5
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity.md5 --body parity.md5
|
||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_arm64.deb" --body "parity_"$VER"_arm64.deb"
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_arm64.deb" --body "parity_"$VER"_arm64.deb"
|
||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_arm64.deb.md5" --body "parity_"$VER"_arm64.deb.md5"
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_arm64.deb.md5" --body "parity_"$VER"_arm64.deb.md5"
|
||||||
# - curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
||||||
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1338/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1338/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
||||||
tags:
|
tags:
|
||||||
- rust
|
- rust
|
||||||
@ -339,28 +374,29 @@ darwin:
|
|||||||
- tags
|
- tags
|
||||||
- stable
|
- stable
|
||||||
- triggers
|
- triggers
|
||||||
script:
|
script: |
|
||||||
- export COMMIT=$(git rev-parse HEAD)
|
export COMMIT=$(git rev-parse HEAD)
|
||||||
- export PLATFORM=x86_64-apple-darwin
|
export PLATFORM=x86_64-apple-darwin
|
||||||
- cargo build -j 8 --features final --release #$CARGOFLAGS
|
cargo build -j 8 --features final --release #$CARGOFLAGS
|
||||||
- cargo build -j 8 --features final --release -p ethstore #$CARGOFLAGS
|
cargo build -j 8 --features final --release -p ethstore #$CARGOFLAGS
|
||||||
- rm -rf parity.md5
|
cargo build -j 8 --features final --release -p evmbin #$CARGOFLAGS
|
||||||
- md5sum target/release/parity > parity.md5
|
rm -rf parity.md5
|
||||||
- export SHA3=$(target/release/parity tools hash target/release/parity)
|
md5sum target/release/parity > parity.md5
|
||||||
- packagesbuild -v mac/Parity.pkgproj
|
export SHA3=$(target/release/parity tools hash target/release/parity)
|
||||||
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
|
packagesbuild -v mac/Parity.pkgproj
|
||||||
- mv target/release/Parity\ Ethereum.pkg "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg"
|
export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
|
||||||
- md5sum "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg" >> "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg.md5"
|
mv target/release/Parity\ Ethereum.pkg "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg"
|
||||||
- aws configure set aws_access_key_id $s3_key
|
md5sum "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg" >> "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg.md5"
|
||||||
- aws configure set aws_secret_access_key $s3_secret
|
aws configure set aws_access_key_id $s3_key
|
||||||
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable)$ ]]; then export S3_BUCKET=builds-parity-published; else export S3_BUCKET=builds-parity; fi
|
aws configure set aws_secret_access_key $s3_secret
|
||||||
- aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/$PLATFORM
|
if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable)$ ]]; then export S3_BUCKET=builds-parity-published; else export S3_BUCKET=builds-parity; fi
|
||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity --body target/release/parity
|
aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/$PLATFORM
|
||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity.md5 --body parity.md5
|
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity --body target/release/parity
|
||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity-"$VER"-osx-installer-EXPERIMENTAL.pkg" --body "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg"
|
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity.md5 --body parity.md5
|
||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity-"$VER"-osx-installer-EXPERIMENTAL.pkg.md5" --body "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg.md5"
|
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity-"$VER"-osx-installer-EXPERIMENTAL.pkg" --body "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg"
|
||||||
# - curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity-"$VER"-osx-installer-EXPERIMENTAL.pkg.md5" --body "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg.md5"
|
||||||
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1338/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
||||||
|
curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1338/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
||||||
tags:
|
tags:
|
||||||
- osx
|
- osx
|
||||||
artifacts:
|
artifacts:
|
||||||
@ -383,7 +419,7 @@ windows:
|
|||||||
- set LIB=C:\vs2015\VC\lib;C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10240.0\ucrt\x64
|
- set LIB=C:\vs2015\VC\lib;C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10240.0\ucrt\x64
|
||||||
- set RUST_BACKTRACE=1
|
- set RUST_BACKTRACE=1
|
||||||
- set RUSTFLAGS=%RUSTFLAGS%
|
- set RUSTFLAGS=%RUSTFLAGS%
|
||||||
- rustup default stable-x86_64-pc-windows-msvc
|
- rustup default 1.14.0-x86_64-pc-windows-msvc
|
||||||
- cargo build --features final --release #%CARGOFLAGS%
|
- cargo build --features final --release #%CARGOFLAGS%
|
||||||
- signtool sign /f %keyfile% /p %certpass% target\release\parity.exe
|
- signtool sign /f %keyfile% /p %certpass% target\release\parity.exe
|
||||||
- target\release\parity.exe tools hash target\release\parity.exe > parity.sha3
|
- target\release\parity.exe tools hash target\release\parity.exe > parity.sha3
|
||||||
@ -421,7 +457,7 @@ windows:
|
|||||||
- aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/InstallParity.exe.md5 --body nsis\InstallParity.exe.md5
|
- aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/InstallParity.exe.md5 --body nsis\InstallParity.exe.md5
|
||||||
- aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/win-installer.zip --body nsis\win-installer.zip
|
- aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/win-installer.zip --body nsis\win-installer.zip
|
||||||
- aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/win-installer.zip.md5 --body nsis\win-installer.zip.md5
|
- aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/win-installer.zip.md5 --body nsis\win-installer.zip.md5
|
||||||
# - curl --data "commit=%CI_BUILD_REF%&sha3=%SHA3%&filename=parity.exe&secret=%RELEASES_SECRET%" http://update.parity.io:1337/push-build/%CI_BUILD_REF_NAME%/%PLATFORM%
|
- curl --data "commit=%CI_BUILD_REF%&sha3=%SHA3%&filename=parity.exe&secret=%RELEASES_SECRET%" http://update.parity.io:1337/push-build/%CI_BUILD_REF_NAME%/%PLATFORM%
|
||||||
- curl --data "commit=%CI_BUILD_REF%&sha3=%SHA3%&filename=parity.exe&secret=%RELEASES_SECRET%" http://update.parity.io:1338/push-build/%CI_BUILD_REF_NAME%/%PLATFORM%
|
- curl --data "commit=%CI_BUILD_REF%&sha3=%SHA3%&filename=parity.exe&secret=%RELEASES_SECRET%" http://update.parity.io:1338/push-build/%CI_BUILD_REF_NAME%/%PLATFORM%
|
||||||
tags:
|
tags:
|
||||||
- rust-windows
|
- rust-windows
|
||||||
@ -431,6 +467,19 @@ windows:
|
|||||||
- target/release/parity.pdb
|
- target/release/parity.pdb
|
||||||
- nsis/InstallParity.exe
|
- nsis/InstallParity.exe
|
||||||
name: "x86_64-pc-windows-msvc_parity"
|
name: "x86_64-pc-windows-msvc_parity"
|
||||||
|
docker-build:
|
||||||
|
stage: build
|
||||||
|
only:
|
||||||
|
- tags
|
||||||
|
- triggers
|
||||||
|
before_script:
|
||||||
|
- docker info
|
||||||
|
script:
|
||||||
|
- if [ "$CI_BUILD_REF_NAME" == "beta-release" ]; then DOCKER_TAG="latest"; else DOCKER_TAG=$CI_BUILD_REF_NAME; fi
|
||||||
|
- docker login -u $Docker_Hub_User -p $Docker_Hub_Pass
|
||||||
|
- sh scripts/docker-build.sh $DOCKER_TAG
|
||||||
|
tags:
|
||||||
|
- docker
|
||||||
test-darwin:
|
test-darwin:
|
||||||
stage: test
|
stage: test
|
||||||
only:
|
only:
|
||||||
@ -452,7 +501,7 @@ test-windows:
|
|||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
script:
|
script:
|
||||||
- set RUST_BACKTRACE=1
|
- set RUST_BACKTRACE=1
|
||||||
- echo cargo test --features json-tests -p rlp -p ethash -p ethcore -p ethcore-bigint -p ethcore-dapps -p ethcore-rpc -p ethcore-signer -p ethcore-util -p ethcore-network -p ethcore-io -p ethkey -p ethstore -p ethsync -p ethcore-ipc -p ethcore-ipc-tests -p ethcore-ipc-nano -p parity %CARGOFLAGS% --verbose --release
|
- echo cargo test --features json-tests -p rlp -p ethash -p ethcore -p ethcore-bigint -p ethcore-dapps -p ethcore-rpc -p ethcore-signer -p ethcore-util -p ethcore-network -p ethcore-io -p ethkey -p ethstore -p evmbin -p ethsync -p ethcore-ipc -p ethcore-ipc-tests -p ethcore-ipc-nano -p parity %CARGOFLAGS% --verbose --release
|
||||||
tags:
|
tags:
|
||||||
- rust-windows
|
- rust-windows
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
@ -529,13 +578,10 @@ js-release:
|
|||||||
push-release:
|
push-release:
|
||||||
stage: push-release
|
stage: push-release
|
||||||
only:
|
only:
|
||||||
- beta
|
|
||||||
- tags
|
- tags
|
||||||
- stable
|
|
||||||
- triggers
|
|
||||||
image: ethcore/rust:stable
|
image: ethcore/rust:stable
|
||||||
script:
|
script:
|
||||||
# - curl --data "secret=$RELEASES_SECRET" http://update.parity.io:1337/push-release/$CI_BUILD_REF_NAME/$CI_BUILD_REF
|
- curl --data "secret=$RELEASES_SECRET" http://update.parity.io:1337/push-release/$CI_BUILD_REF_NAME/$CI_BUILD_REF
|
||||||
- curl --data "secret=$RELEASES_SECRET" http://update.parity.io:1338/push-release/$CI_BUILD_REF_NAME/$CI_BUILD_REF
|
- curl --data "secret=$RELEASES_SECRET" http://update.parity.io:1338/push-release/$CI_BUILD_REF_NAME/$CI_BUILD_REF
|
||||||
tags:
|
tags:
|
||||||
- curl
|
- curl
|
||||||
|
202
Cargo.lock
generated
202
Cargo.lock
generated
@ -1,6 +1,6 @@
|
|||||||
[root]
|
[root]
|
||||||
name = "parity"
|
name = "parity"
|
||||||
version = "1.5.0"
|
version = "1.5.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -23,8 +23,9 @@ dependencies = [
|
|||||||
"ethcore-rpc 1.5.0",
|
"ethcore-rpc 1.5.0",
|
||||||
"ethcore-signer 1.5.0",
|
"ethcore-signer 1.5.0",
|
||||||
"ethcore-stratum 1.5.0",
|
"ethcore-stratum 1.5.0",
|
||||||
"ethcore-util 1.5.0",
|
"ethcore-util 1.5.8",
|
||||||
"ethsync 1.5.0",
|
"ethsync 1.5.0",
|
||||||
|
"evmbin 1.5.0",
|
||||||
"fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hyper 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hyper 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -72,6 +73,11 @@ name = "ansi_term"
|
|||||||
version = "0.7.2"
|
version = "0.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "antidote"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "app_dirs"
|
name = "app_dirs"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
@ -292,6 +298,11 @@ name = "dtoa"
|
|||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dtoa"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "elastic-array"
|
name = "elastic-array"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
@ -362,7 +373,7 @@ dependencies = [
|
|||||||
"ethcore-ipc 1.5.0",
|
"ethcore-ipc 1.5.0",
|
||||||
"ethcore-ipc-codegen 1.5.0",
|
"ethcore-ipc-codegen 1.5.0",
|
||||||
"ethcore-ipc-nano 1.5.0",
|
"ethcore-ipc-nano 1.5.0",
|
||||||
"ethcore-util 1.5.0",
|
"ethcore-util 1.5.8",
|
||||||
"ethjson 0.1.0",
|
"ethjson 0.1.0",
|
||||||
"ethkey 0.2.0",
|
"ethkey 0.2.0",
|
||||||
"ethstore 0.1.0",
|
"ethstore 0.1.0",
|
||||||
@ -390,6 +401,7 @@ version = "0.1.2"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bigint 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bigint 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@ -409,12 +421,12 @@ dependencies = [
|
|||||||
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ethcore-devtools 1.5.0",
|
"ethcore-devtools 1.5.0",
|
||||||
"ethcore-rpc 1.5.0",
|
"ethcore-rpc 1.5.0",
|
||||||
"ethcore-util 1.5.0",
|
"ethcore-util 1.5.8",
|
||||||
"fetch 0.1.0",
|
"fetch 0.1.0",
|
||||||
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)",
|
"hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)",
|
||||||
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
|
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)",
|
||||||
"jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc.git)",
|
"jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)",
|
||||||
"linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -457,7 +469,7 @@ name = "ethcore-ipc"
|
|||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ethcore-devtools 1.5.0",
|
"ethcore-devtools 1.5.0",
|
||||||
"ethcore-util 1.5.0",
|
"ethcore-util 1.5.8",
|
||||||
"nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)",
|
"nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)",
|
||||||
"semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@ -504,7 +516,7 @@ dependencies = [
|
|||||||
"ethcore-ipc 1.5.0",
|
"ethcore-ipc 1.5.0",
|
||||||
"ethcore-ipc-codegen 1.5.0",
|
"ethcore-ipc-codegen 1.5.0",
|
||||||
"ethcore-ipc-nano 1.5.0",
|
"ethcore-ipc-nano 1.5.0",
|
||||||
"ethcore-util 1.5.0",
|
"ethcore-util 1.5.8",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)",
|
"nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)",
|
||||||
"semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -519,7 +531,7 @@ dependencies = [
|
|||||||
"ethcore-ipc 1.5.0",
|
"ethcore-ipc 1.5.0",
|
||||||
"ethcore-ipc-codegen 1.5.0",
|
"ethcore-ipc-codegen 1.5.0",
|
||||||
"ethcore-network 1.5.0",
|
"ethcore-network 1.5.0",
|
||||||
"ethcore-util 1.5.0",
|
"ethcore-util 1.5.8",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rlp 0.1.0",
|
"rlp 0.1.0",
|
||||||
"smallvec 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"smallvec 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -531,7 +543,7 @@ name = "ethcore-logger"
|
|||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ethcore-util 1.5.0",
|
"ethcore-util 1.5.8",
|
||||||
"isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -547,7 +559,7 @@ dependencies = [
|
|||||||
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ethcore-devtools 1.5.0",
|
"ethcore-devtools 1.5.0",
|
||||||
"ethcore-io 1.5.0",
|
"ethcore-io 1.5.0",
|
||||||
"ethcore-util 1.5.0",
|
"ethcore-util 1.5.8",
|
||||||
"ethcrypto 0.1.0",
|
"ethcrypto 0.1.0",
|
||||||
"ethkey 0.2.0",
|
"ethkey 0.2.0",
|
||||||
"igd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"igd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -574,7 +586,7 @@ dependencies = [
|
|||||||
"ethcore-devtools 1.5.0",
|
"ethcore-devtools 1.5.0",
|
||||||
"ethcore-io 1.5.0",
|
"ethcore-io 1.5.0",
|
||||||
"ethcore-ipc 1.5.0",
|
"ethcore-ipc 1.5.0",
|
||||||
"ethcore-util 1.5.0",
|
"ethcore-util 1.5.8",
|
||||||
"ethcrypto 0.1.0",
|
"ethcrypto 0.1.0",
|
||||||
"ethjson 0.1.0",
|
"ethjson 0.1.0",
|
||||||
"ethkey 0.2.0",
|
"ethkey 0.2.0",
|
||||||
@ -582,10 +594,10 @@ dependencies = [
|
|||||||
"ethsync 1.5.0",
|
"ethsync 1.5.0",
|
||||||
"fetch 0.1.0",
|
"fetch 0.1.0",
|
||||||
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
|
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)",
|
||||||
"jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc.git)",
|
"jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)",
|
||||||
"jsonrpc-ipc-server 0.2.4 (git+https://github.com/ethcore/jsonrpc.git)",
|
"jsonrpc-ipc-server 0.2.4 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)",
|
||||||
"jsonrpc-macros 0.1.0 (git+https://github.com/ethcore/jsonrpc.git)",
|
"jsonrpc-macros 0.1.0 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parity-reactor 0.1.0",
|
"parity-reactor 0.1.0",
|
||||||
"parity-updater 1.5.0",
|
"parity-updater 1.5.0",
|
||||||
@ -609,8 +621,8 @@ dependencies = [
|
|||||||
"ethcore-devtools 1.5.0",
|
"ethcore-devtools 1.5.0",
|
||||||
"ethcore-io 1.5.0",
|
"ethcore-io 1.5.0",
|
||||||
"ethcore-rpc 1.5.0",
|
"ethcore-rpc 1.5.0",
|
||||||
"ethcore-util 1.5.0",
|
"ethcore-util 1.5.8",
|
||||||
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
|
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parity-ui 1.5.0",
|
"parity-ui 1.5.0",
|
||||||
@ -628,9 +640,9 @@ dependencies = [
|
|||||||
"ethcore-ipc 1.5.0",
|
"ethcore-ipc 1.5.0",
|
||||||
"ethcore-ipc-codegen 1.5.0",
|
"ethcore-ipc-codegen 1.5.0",
|
||||||
"ethcore-ipc-nano 1.5.0",
|
"ethcore-ipc-nano 1.5.0",
|
||||||
"ethcore-util 1.5.0",
|
"ethcore-util 1.5.8",
|
||||||
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
|
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)",
|
||||||
"jsonrpc-tcp-server 0.1.0 (git+https://github.com/ethcore/jsonrpc.git)",
|
"jsonrpc-tcp-server 0.1.0 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)",
|
||||||
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)",
|
"mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)",
|
||||||
@ -639,7 +651,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ethcore-util"
|
name = "ethcore-util"
|
||||||
version = "1.5.0"
|
version = "1.5.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
"arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -688,7 +700,7 @@ dependencies = [
|
|||||||
name = "ethjson"
|
name = "ethjson"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ethcore-util 1.5.0",
|
"ethcore-util 1.5.8",
|
||||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_codegen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_codegen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -744,7 +756,7 @@ dependencies = [
|
|||||||
"ethcore-ipc-nano 1.5.0",
|
"ethcore-ipc-nano 1.5.0",
|
||||||
"ethcore-light 1.5.0",
|
"ethcore-light 1.5.0",
|
||||||
"ethcore-network 1.5.0",
|
"ethcore-network 1.5.0",
|
||||||
"ethcore-util 1.5.0",
|
"ethcore-util 1.5.8",
|
||||||
"ethkey 0.2.0",
|
"ethkey 0.2.0",
|
||||||
"heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -755,6 +767,16 @@ dependencies = [
|
|||||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "evmbin"
|
||||||
|
version = "1.5.0"
|
||||||
|
dependencies = [
|
||||||
|
"docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ethcore 1.5.0",
|
||||||
|
"ethcore-util 1.5.8",
|
||||||
|
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "evmjit"
|
name = "evmjit"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
@ -778,7 +800,8 @@ dependencies = [
|
|||||||
"futures-cpupool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures-cpupool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"reqwest 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"reqwest 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -879,7 +902,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "0.10.0-a.0"
|
version = "0.10.0-a.0"
|
||||||
source = "git+https://github.com/ethcore/hyper#7d4f7fa0baddcb2b0c523f7c05855d67de94fe88"
|
source = "git+https://github.com/ethcore/hyper#6baea9d444dd1652220ee9b4aeadaebb3de6a955"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cookie 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cookie 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -895,6 +918,35 @@ dependencies = [
|
|||||||
"vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper"
|
||||||
|
version = "0.10.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num_cpus 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-native-tls"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"hyper 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"native-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -923,7 +975,7 @@ version = "1.5.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"ethcore-ipc 1.5.0",
|
"ethcore-ipc 1.5.0",
|
||||||
"ethcore-ipc-codegen 1.5.0",
|
"ethcore-ipc-codegen 1.5.0",
|
||||||
"ethcore-util 1.5.0",
|
"ethcore-util 1.5.8",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@ -948,10 +1000,15 @@ name = "itoa"
|
|||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-core"
|
name = "jsonrpc-core"
|
||||||
version = "4.0.0"
|
version = "4.0.0"
|
||||||
source = "git+https://github.com/ethcore/jsonrpc.git#33262d626a294a00c20435dec331058ba65e224a"
|
source = "git+https://github.com/ethcore/jsonrpc.git?branch=mio-old#057cc58a849d18933a9cce60a33559c7505bd7ce"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -963,10 +1020,10 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-http-server"
|
name = "jsonrpc-http-server"
|
||||||
version = "6.1.1"
|
version = "6.1.1"
|
||||||
source = "git+https://github.com/ethcore/jsonrpc.git#33262d626a294a00c20435dec331058ba65e224a"
|
source = "git+https://github.com/ethcore/jsonrpc.git?branch=mio-old#057cc58a849d18933a9cce60a33559c7505bd7ce"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)",
|
"hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)",
|
||||||
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
|
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@ -974,11 +1031,11 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-ipc-server"
|
name = "jsonrpc-ipc-server"
|
||||||
version = "0.2.4"
|
version = "0.2.4"
|
||||||
source = "git+https://github.com/ethcore/jsonrpc.git#33262d626a294a00c20435dec331058ba65e224a"
|
source = "git+https://github.com/ethcore/jsonrpc.git?branch=mio-old#057cc58a849d18933a9cce60a33559c7505bd7ce"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
|
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)",
|
||||||
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -989,20 +1046,20 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-macros"
|
name = "jsonrpc-macros"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/ethcore/jsonrpc.git#33262d626a294a00c20435dec331058ba65e224a"
|
source = "git+https://github.com/ethcore/jsonrpc.git?branch=mio-old#057cc58a849d18933a9cce60a33559c7505bd7ce"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
|
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)",
|
||||||
"serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-tcp-server"
|
name = "jsonrpc-tcp-server"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/ethcore/jsonrpc.git#33262d626a294a00c20435dec331058ba65e224a"
|
source = "git+https://github.com/ethcore/jsonrpc.git?branch=mio-old#057cc58a849d18933a9cce60a33559c7505bd7ce"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
|
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)",
|
||||||
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1443,7 +1500,7 @@ name = "parity-hash-fetch"
|
|||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ethabi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ethabi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ethcore-util 1.5.0",
|
"ethcore-util 1.5.8",
|
||||||
"fetch 0.1.0",
|
"fetch 0.1.0",
|
||||||
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1468,9 +1525,9 @@ version = "1.4.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"ethcore-rpc 1.5.0",
|
"ethcore-rpc 1.5.0",
|
||||||
"ethcore-signer 1.5.0",
|
"ethcore-signer 1.5.0",
|
||||||
"ethcore-util 1.5.0",
|
"ethcore-util 1.5.8",
|
||||||
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
|
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)",
|
||||||
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1487,7 +1544,7 @@ name = "parity-ui"
|
|||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-ui-dev 1.4.0",
|
"parity-ui-dev 1.4.0",
|
||||||
"parity-ui-precompiled 1.4.0 (git+https://github.com/ethcore/js-precompiled.git)",
|
"parity-ui-precompiled 1.4.0 (git+https://github.com/ethcore/js-precompiled.git?branch=stable)",
|
||||||
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1501,7 +1558,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "parity-ui-precompiled"
|
name = "parity-ui-precompiled"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
source = "git+https://github.com/ethcore/js-precompiled.git#66ef86da6f741953694199813e1eb6b76b3f5b5f"
|
source = "git+https://github.com/ethcore/js-precompiled.git?branch=stable#9fb19b623adc025b0f173fbcbd197f41b03770d5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@ -1514,7 +1571,7 @@ dependencies = [
|
|||||||
"ethcore 1.5.0",
|
"ethcore 1.5.0",
|
||||||
"ethcore-ipc 1.5.0",
|
"ethcore-ipc 1.5.0",
|
||||||
"ethcore-ipc-codegen 1.5.0",
|
"ethcore-ipc-codegen 1.5.0",
|
||||||
"ethcore-util 1.5.0",
|
"ethcore-util 1.5.8",
|
||||||
"ethsync 1.5.0",
|
"ethsync 1.5.0",
|
||||||
"ipc-common-types 1.5.0",
|
"ipc-common-types 1.5.0",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1714,15 +1771,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.2.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hyper 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hyper 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"hyper-native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"native-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_urlencoded 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_urlencoded 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1794,7 +1851,7 @@ version = "1.4.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"ethcore-bigint 0.1.2",
|
"ethcore-bigint 0.1.2",
|
||||||
"ethcore-rpc 1.5.0",
|
"ethcore-rpc 1.5.0",
|
||||||
"ethcore-util 1.5.0",
|
"ethcore-util 1.5.8",
|
||||||
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parity-rpc-client 1.4.0",
|
"parity-rpc-client 1.4.0",
|
||||||
"rpassword 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rpassword 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1908,6 +1965,11 @@ name = "serde"
|
|||||||
version = "0.8.19"
|
version = "0.8.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "0.9.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_codegen"
|
name = "serde_codegen"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
@ -1942,11 +2004,24 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_urlencoded"
|
name = "serde_json"
|
||||||
version = "0.3.0"
|
version = "0.9.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
"dtoa 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"itoa 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_urlencoded"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"dtoa 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"itoa 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2363,6 +2438,7 @@ dependencies = [
|
|||||||
"checksum advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a"
|
"checksum advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a"
|
||||||
"checksum aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67077478f0a03952bed2e6786338d400d40c25e9836e08ad50af96607317fd03"
|
"checksum aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67077478f0a03952bed2e6786338d400d40c25e9836e08ad50af96607317fd03"
|
||||||
"checksum ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1f46cd5b1d660c938e3f92dfe7a73d832b3281479363dd0cd9c1c2fbf60f7962"
|
"checksum ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1f46cd5b1d660c938e3f92dfe7a73d832b3281479363dd0cd9c1c2fbf60f7962"
|
||||||
|
"checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5"
|
||||||
"checksum app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7d1c0d48a81bbb13043847f957971f4d87c81542d80ece5e84ba3cba4058fd4"
|
"checksum app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7d1c0d48a81bbb13043847f957971f4d87c81542d80ece5e84ba3cba4058fd4"
|
||||||
"checksum arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "16e3bdb2f54b3ace0285975d59a97cf8ed3855294b2b6bc651fcf22a9c352975"
|
"checksum arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "16e3bdb2f54b3ace0285975d59a97cf8ed3855294b2b6bc651fcf22a9c352975"
|
||||||
"checksum aster 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07d344974f0a155f091948aa389fb1b912d3a58414fbdb9c8d446d193ee3496a"
|
"checksum aster 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07d344974f0a155f091948aa389fb1b912d3a58414fbdb9c8d446d193ee3496a"
|
||||||
@ -2392,6 +2468,7 @@ dependencies = [
|
|||||||
"checksum deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1614659040e711785ed8ea24219140654da1729f3ec8a47a9719d041112fe7bf"
|
"checksum deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1614659040e711785ed8ea24219140654da1729f3ec8a47a9719d041112fe7bf"
|
||||||
"checksum docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4cc0acb4ce0828c6a5a11d47baa432fe885881c27428c3a4e473e454ffe57a76"
|
"checksum docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4cc0acb4ce0828c6a5a11d47baa432fe885881c27428c3a4e473e454ffe57a76"
|
||||||
"checksum dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd841b58510c9618291ffa448da2e4e0f699d984d436122372f446dae62263d"
|
"checksum dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd841b58510c9618291ffa448da2e4e0f699d984d436122372f446dae62263d"
|
||||||
|
"checksum dtoa 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5edd69c67b2f8e0911629b7e6b8a34cb3956613cd7c6e6414966dee349c2db4f"
|
||||||
"checksum elastic-array 0.6.0 (git+https://github.com/ethcore/elastic-array)" = "<none>"
|
"checksum elastic-array 0.6.0 (git+https://github.com/ethcore/elastic-array)" = "<none>"
|
||||||
"checksum env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aba65b63ffcc17ffacd6cf5aa843da7c5a25e3bd4bbe0b7def8b214e411250e5"
|
"checksum env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aba65b63ffcc17ffacd6cf5aa843da7c5a25e3bd4bbe0b7def8b214e411250e5"
|
||||||
"checksum eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)" = "<none>"
|
"checksum eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)" = "<none>"
|
||||||
@ -2408,17 +2485,20 @@ dependencies = [
|
|||||||
"checksum hpack 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2da7d3a34cf6406d9d700111b8eafafe9a251de41ae71d8052748259343b58"
|
"checksum hpack 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2da7d3a34cf6406d9d700111b8eafafe9a251de41ae71d8052748259343b58"
|
||||||
"checksum httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46534074dbb80b070d60a5cb8ecadd8963a00a438ae1a95268850a7ef73b67ae"
|
"checksum httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46534074dbb80b070d60a5cb8ecadd8963a00a438ae1a95268850a7ef73b67ae"
|
||||||
"checksum hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)" = "<none>"
|
"checksum hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)" = "<none>"
|
||||||
|
"checksum hyper 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "220407e5a263f110ec30a071787c9535918fdfc97def5680c90013c3f30c38c1"
|
||||||
"checksum hyper 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)" = "bcb3fc65554155980167fb821d05c7c66177f92464976c0b676a19d9e03387a7"
|
"checksum hyper 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)" = "bcb3fc65554155980167fb821d05c7c66177f92464976c0b676a19d9e03387a7"
|
||||||
|
"checksum hyper-native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "afe68f772f0497a7205e751626bb8e1718568b58534b6108c73a74ef80483409"
|
||||||
"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11"
|
"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11"
|
||||||
"checksum igd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c8c12b1795b8b168f577c45fa10379b3814dcb11b7ab702406001f0d63f40484"
|
"checksum igd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c8c12b1795b8b168f577c45fa10379b3814dcb11b7ab702406001f0d63f40484"
|
||||||
"checksum isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7408a548dc0e406b7912d9f84c261cc533c1866e047644a811c133c56041ac0c"
|
"checksum isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7408a548dc0e406b7912d9f84c261cc533c1866e047644a811c133c56041ac0c"
|
||||||
"checksum itertools 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "086e1fa5fe48840b1cfdef3a20c7e3115599f8d5c4c87ef32a794a7cdd184d76"
|
"checksum itertools 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "086e1fa5fe48840b1cfdef3a20c7e3115599f8d5c4c87ef32a794a7cdd184d76"
|
||||||
"checksum itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3088ea4baeceb0284ee9eea42f591226e6beaecf65373e41b38d95a1b8e7a1"
|
"checksum itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3088ea4baeceb0284ee9eea42f591226e6beaecf65373e41b38d95a1b8e7a1"
|
||||||
"checksum jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)" = "<none>"
|
"checksum itoa 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91fd9dc2c587067de817fec4ad355e3818c3d893a78cab32a0a474c7a15bb8d5"
|
||||||
"checksum jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc.git)" = "<none>"
|
"checksum jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)" = "<none>"
|
||||||
"checksum jsonrpc-ipc-server 0.2.4 (git+https://github.com/ethcore/jsonrpc.git)" = "<none>"
|
"checksum jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)" = "<none>"
|
||||||
"checksum jsonrpc-macros 0.1.0 (git+https://github.com/ethcore/jsonrpc.git)" = "<none>"
|
"checksum jsonrpc-ipc-server 0.2.4 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)" = "<none>"
|
||||||
"checksum jsonrpc-tcp-server 0.1.0 (git+https://github.com/ethcore/jsonrpc.git)" = "<none>"
|
"checksum jsonrpc-macros 0.1.0 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)" = "<none>"
|
||||||
|
"checksum jsonrpc-tcp-server 0.1.0 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)" = "<none>"
|
||||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||||
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
|
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
|
||||||
"checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"
|
"checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"
|
||||||
@ -2465,7 +2545,7 @@ dependencies = [
|
|||||||
"checksum openssl-sys 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d2845e841700e7b04282ceaa115407ea84e0db918ae689ad9ceb6f06fa6046bd"
|
"checksum openssl-sys 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d2845e841700e7b04282ceaa115407ea84e0db918ae689ad9ceb6f06fa6046bd"
|
||||||
"checksum owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8d91377085359426407a287ab16884a0111ba473aa6844ff01d4ec20ce3d75e7"
|
"checksum owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8d91377085359426407a287ab16884a0111ba473aa6844ff01d4ec20ce3d75e7"
|
||||||
"checksum parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98378dec0a185da2b7180308752f0bad73aaa949c3e0a3b0528d0e067945f7ab"
|
"checksum parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98378dec0a185da2b7180308752f0bad73aaa949c3e0a3b0528d0e067945f7ab"
|
||||||
"checksum parity-ui-precompiled 1.4.0 (git+https://github.com/ethcore/js-precompiled.git)" = "<none>"
|
"checksum parity-ui-precompiled 1.4.0 (git+https://github.com/ethcore/js-precompiled.git?branch=stable)" = "<none>"
|
||||||
"checksum parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e1435e7a2a00dfebededd6c6bdbd54008001e94b4a2aadd6aef0dc4c56317621"
|
"checksum parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e1435e7a2a00dfebededd6c6bdbd54008001e94b4a2aadd6aef0dc4c56317621"
|
||||||
"checksum parking_lot_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb1b97670a2ffadce7c397fb80a3d687c4f3060140b885621ef1653d0e5d5068"
|
"checksum parking_lot_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb1b97670a2ffadce7c397fb80a3d687c4f3060140b885621ef1653d0e5d5068"
|
||||||
"checksum phf 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "447d9d45f2e0b4a9b532e808365abf18fc211be6ca217202fcd45236ef12f026"
|
"checksum phf 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "447d9d45f2e0b4a9b532e808365abf18fc211be6ca217202fcd45236ef12f026"
|
||||||
@ -2489,7 +2569,7 @@ dependencies = [
|
|||||||
"checksum rayon 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "655df67c314c30fa3055a365eae276eb88aa4f3413a352a1ab32c1320eda41ea"
|
"checksum rayon 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "655df67c314c30fa3055a365eae276eb88aa4f3413a352a1ab32c1320eda41ea"
|
||||||
"checksum regex 0.1.68 (registry+https://github.com/rust-lang/crates.io-index)" = "b4329b8928a284580a1c63ec9d846b12f6d3472317243ff7077aff11f23f2b29"
|
"checksum regex 0.1.68 (registry+https://github.com/rust-lang/crates.io-index)" = "b4329b8928a284580a1c63ec9d846b12f6d3472317243ff7077aff11f23f2b29"
|
||||||
"checksum regex-syntax 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "841591b1e05609a643e3b4d0045fce04f701daba7151ddcd3ad47b080693d5a9"
|
"checksum regex-syntax 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "841591b1e05609a643e3b4d0045fce04f701daba7151ddcd3ad47b080693d5a9"
|
||||||
"checksum reqwest 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83186fee0d4dbeb95e610b77b05b05cf5b31703dd375222acb74c3dff4be957c"
|
"checksum reqwest 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bef9ed8fdfcc30947d6b774938dc0c3f369a474efe440df2c7f278180b2d2e6"
|
||||||
"checksum rocksdb 0.4.5 (git+https://github.com/ethcore/rust-rocksdb)" = "<none>"
|
"checksum rocksdb 0.4.5 (git+https://github.com/ethcore/rust-rocksdb)" = "<none>"
|
||||||
"checksum rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)" = "<none>"
|
"checksum rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)" = "<none>"
|
||||||
"checksum rotor 0.6.3 (git+https://github.com/ethcore/rotor)" = "<none>"
|
"checksum rotor 0.6.3 (git+https://github.com/ethcore/rotor)" = "<none>"
|
||||||
@ -2508,10 +2588,12 @@ dependencies = [
|
|||||||
"checksum semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae2ff60ecdb19c255841c066cbfa5f8c2a4ada1eb3ae47c77ab6667128da71f5"
|
"checksum semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae2ff60ecdb19c255841c066cbfa5f8c2a4ada1eb3ae47c77ab6667128da71f5"
|
||||||
"checksum semver-parser 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e88e43a5a74dd2a11707f9c21dfd4a423c66bd871df813227bb0a3e78f3a1ae9"
|
"checksum semver-parser 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e88e43a5a74dd2a11707f9c21dfd4a423c66bd871df813227bb0a3e78f3a1ae9"
|
||||||
"checksum serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)" = "58a19c0871c298847e6b68318484685cd51fa5478c0c905095647540031356e5"
|
"checksum serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)" = "58a19c0871c298847e6b68318484685cd51fa5478c0c905095647540031356e5"
|
||||||
|
"checksum serde 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4d8f810025e9d09c4eaa49c16eaf878f34a947889e878cd7d3b5bef3197cc119"
|
||||||
"checksum serde_codegen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e422ae53d7933f59c6ff57e7b5870b5c9094b1f473f78ec33d89f8a692c3ec02"
|
"checksum serde_codegen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e422ae53d7933f59c6ff57e7b5870b5c9094b1f473f78ec33d89f8a692c3ec02"
|
||||||
"checksum serde_codegen_internals 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f877e2781ed0a323295d1c9f0e26556117b5a11489fc47b1848dfb98b3173d21"
|
"checksum serde_codegen_internals 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f877e2781ed0a323295d1c9f0e26556117b5a11489fc47b1848dfb98b3173d21"
|
||||||
"checksum serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e10f8a9d94b06cf5d3bef66475f04c8ff90950f1be7004c357ff9472ccbaebc"
|
"checksum serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e10f8a9d94b06cf5d3bef66475f04c8ff90950f1be7004c357ff9472ccbaebc"
|
||||||
"checksum serde_urlencoded 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "53d4ebaa8d1d4f90d1b63dfca81ccd98ac20e1e479dbae393cbaf60f6fecd8d8"
|
"checksum serde_json 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fea48f4d4df4e620e3c81fd2bf28c93dd0d266361a76bac4f254b71f0e13f3cd"
|
||||||
|
"checksum serde_urlencoded 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a81f15da4b9780e1524697f73b09076b6e42298ef673bead9ca8f848b334ef84"
|
||||||
"checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c"
|
"checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c"
|
||||||
"checksum shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72f20b8f3c060374edb8046591ba28f62448c369ccbdc7b02075103fb3a9e38d"
|
"checksum shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72f20b8f3c060374edb8046591ba28f62448c369ccbdc7b02075103fb3a9e38d"
|
||||||
"checksum siphasher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c44e42fa187b5a8782489cf7740cc27c3125806be2bf33563cf5e02e9533fcd"
|
"checksum siphasher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c44e42fa187b5a8782489cf7740cc27c3125806be2bf33563cf5e02e9533fcd"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
description = "Parity Ethereum client"
|
description = "Parity Ethereum client"
|
||||||
name = "parity"
|
name = "parity"
|
||||||
version = "1.5.0"
|
version = "1.5.8"
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
authors = ["Parity Technologies <admin@parity.io>"]
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
@ -47,6 +47,7 @@ ethcore-ipc-hypervisor = { path = "ipc/hypervisor" }
|
|||||||
ethcore-logger = { path = "logger" }
|
ethcore-logger = { path = "logger" }
|
||||||
ethcore-stratum = { path = "stratum" }
|
ethcore-stratum = { path = "stratum" }
|
||||||
ethcore-dapps = { path = "dapps", optional = true }
|
ethcore-dapps = { path = "dapps", optional = true }
|
||||||
|
evmbin = { path = "evmbin" }
|
||||||
rpc-cli = { path = "rpc_cli" }
|
rpc-cli = { path = "rpc_cli" }
|
||||||
parity-rpc-client = { path = "rpc_client" }
|
parity-rpc-client = { path = "rpc_client" }
|
||||||
ethcore-light = { path = "ethcore/light" }
|
ethcore-light = { path = "ethcore/light" }
|
||||||
|
@ -13,8 +13,8 @@ rand = "0.3"
|
|||||||
log = "0.3"
|
log = "0.3"
|
||||||
env_logger = "0.3"
|
env_logger = "0.3"
|
||||||
futures = "0.1"
|
futures = "0.1"
|
||||||
jsonrpc-core = { git = "https://github.com/ethcore/jsonrpc.git" }
|
jsonrpc-core = { git = "https://github.com/ethcore/jsonrpc.git", branch="mio-old" }
|
||||||
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc.git" }
|
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc.git", branch="mio-old" }
|
||||||
hyper = { default-features = false, git = "https://github.com/ethcore/hyper" }
|
hyper = { default-features = false, git = "https://github.com/ethcore/hyper" }
|
||||||
unicase = "1.3"
|
unicase = "1.3"
|
||||||
url = "1.0"
|
url = "1.0"
|
||||||
|
@ -38,6 +38,7 @@ pub const RPC_PATH: &'static str = "rpc";
|
|||||||
pub const API_PATH: &'static str = "api";
|
pub const API_PATH: &'static str = "api";
|
||||||
pub const UTILS_PATH: &'static str = "parity-utils";
|
pub const UTILS_PATH: &'static str = "parity-utils";
|
||||||
pub const WEB_PATH: &'static str = "web";
|
pub const WEB_PATH: &'static str = "web";
|
||||||
|
pub const URL_REFERER: &'static str = "__referer=";
|
||||||
|
|
||||||
pub fn utils() -> Box<Endpoint> {
|
pub fn utils() -> Box<Endpoint> {
|
||||||
Box::new(PageEndpoint::with_prefix(parity_ui::App::default(), UTILS_PATH.to_owned()))
|
Box::new(PageEndpoint::with_prefix(parity_ui::App::default(), UTILS_PATH.to_owned()))
|
||||||
|
@ -34,7 +34,7 @@ use endpoint::EndpointPath;
|
|||||||
use handlers::{ContentHandler, StreamingHandler};
|
use handlers::{ContentHandler, StreamingHandler};
|
||||||
use page::{LocalPageEndpoint, PageHandlerWaiting};
|
use page::{LocalPageEndpoint, PageHandlerWaiting};
|
||||||
|
|
||||||
const FETCH_TIMEOUT: u64 = 30;
|
const FETCH_TIMEOUT: u64 = 300;
|
||||||
|
|
||||||
pub enum ValidatorResponse {
|
pub enum ValidatorResponse {
|
||||||
Local(LocalPageEndpoint),
|
Local(LocalPageEndpoint),
|
||||||
|
@ -312,7 +312,7 @@ impl Server {
|
|||||||
|
|
||||||
let special = Arc::new({
|
let special = Arc::new({
|
||||||
let mut special = HashMap::new();
|
let mut special = HashMap::new();
|
||||||
special.insert(router::SpecialEndpoint::Rpc, rpc::rpc(handler, panic_handler.clone()));
|
special.insert(router::SpecialEndpoint::Rpc, rpc::rpc(handler, cors_domains.clone(), panic_handler.clone()));
|
||||||
special.insert(router::SpecialEndpoint::Utils, apps::utils());
|
special.insert(router::SpecialEndpoint::Utils, apps::utils());
|
||||||
special.insert(
|
special.insert(
|
||||||
router::SpecialEndpoint::Api,
|
router::SpecialEndpoint::Api,
|
||||||
|
@ -56,7 +56,6 @@ pub struct Router<A: Authorization + 'static> {
|
|||||||
impl<A: Authorization + 'static> server::Handler<HttpStream> for Router<A> {
|
impl<A: Authorization + 'static> server::Handler<HttpStream> for Router<A> {
|
||||||
|
|
||||||
fn on_request(&mut self, req: server::Request<HttpStream>) -> Next {
|
fn on_request(&mut self, req: server::Request<HttpStream>) -> Next {
|
||||||
|
|
||||||
// Choose proper handler depending on path / domain
|
// Choose proper handler depending on path / domain
|
||||||
let url = handlers::extract_url(&req);
|
let url = handlers::extract_url(&req);
|
||||||
let endpoint = extract_endpoint(&url);
|
let endpoint = extract_endpoint(&url);
|
||||||
@ -92,8 +91,7 @@ impl<A: Authorization + 'static> server::Handler<HttpStream> for Router<A> {
|
|||||||
self.handler = match (endpoint.0, endpoint.1, referer) {
|
self.handler = match (endpoint.0, endpoint.1, referer) {
|
||||||
// Handle invalid web requests that we can recover from
|
// Handle invalid web requests that we can recover from
|
||||||
(ref path, SpecialEndpoint::None, Some((ref referer, ref referer_url)))
|
(ref path, SpecialEndpoint::None, Some((ref referer, ref referer_url)))
|
||||||
if is_get_request
|
if referer.app_id == apps::WEB_PATH
|
||||||
&& referer.app_id == apps::WEB_PATH
|
|
||||||
&& self.endpoints.contains_key(apps::WEB_PATH)
|
&& self.endpoints.contains_key(apps::WEB_PATH)
|
||||||
&& !is_web_endpoint(path)
|
&& !is_web_endpoint(path)
|
||||||
=>
|
=>
|
||||||
@ -225,8 +223,26 @@ fn extract_referer_endpoint(req: &server::Request<HttpStream>) -> Option<(Endpoi
|
|||||||
let url = referer.and_then(|referer| Url::parse(&referer.0).ok());
|
let url = referer.and_then(|referer| Url::parse(&referer.0).ok());
|
||||||
url.and_then(|url| {
|
url.and_then(|url| {
|
||||||
let option = Some(url);
|
let option = Some(url);
|
||||||
|
extract_url_referer_endpoint(&option).or_else(|| {
|
||||||
extract_endpoint(&option).0.map(|endpoint| (endpoint, option.expect("Just wrapped; qed")))
|
extract_endpoint(&option).0.map(|endpoint| (endpoint, option.expect("Just wrapped; qed")))
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_url_referer_endpoint(url: &Option<Url>) -> Option<(EndpointPath, Url)> {
|
||||||
|
let query = url.as_ref().and_then(|url| url.query.as_ref());
|
||||||
|
match (url, query) {
|
||||||
|
(&Some(ref url), Some(ref query)) if query.starts_with(apps::URL_REFERER) => {
|
||||||
|
let referer_url = format!("http://{}:{}/{}", url.host, url.port, &query[apps::URL_REFERER.len()..]);
|
||||||
|
debug!(target: "dapps", "Recovering referer from query parameter: {}", referer_url);
|
||||||
|
|
||||||
|
let referer_url = Url::parse(&referer_url).ok();
|
||||||
|
extract_endpoint(&referer_url).0.map(|endpoint| {
|
||||||
|
(endpoint, referer_url.expect("Endpoint returned only when url `is_some`").clone())
|
||||||
|
})
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_endpoint(url: &Option<Url>) -> (Option<EndpointPath>, SpecialEndpoint) {
|
fn extract_endpoint(url: &Option<Url>) -> (Option<EndpointPath>, SpecialEndpoint) {
|
||||||
|
@ -21,11 +21,15 @@ use jsonrpc_core::{IoHandler, ResponseHandler, Request, Response};
|
|||||||
use jsonrpc_http_server::{ServerHandler, PanicHandler, AccessControlAllowOrigin, RpcHandler};
|
use jsonrpc_http_server::{ServerHandler, PanicHandler, AccessControlAllowOrigin, RpcHandler};
|
||||||
use endpoint::{Endpoint, EndpointPath, Handler};
|
use endpoint::{Endpoint, EndpointPath, Handler};
|
||||||
|
|
||||||
pub fn rpc(handler: Arc<IoHandler>, panic_handler: Arc<Mutex<Option<Box<Fn() -> () + Send>>>>) -> Box<Endpoint> {
|
pub fn rpc(
|
||||||
|
handler: Arc<IoHandler>,
|
||||||
|
cors_domains: Vec<String>,
|
||||||
|
panic_handler: Arc<Mutex<Option<Box<Fn() -> () + Send>>>>,
|
||||||
|
) -> Box<Endpoint> {
|
||||||
Box::new(RpcEndpoint {
|
Box::new(RpcEndpoint {
|
||||||
handler: Arc::new(RpcMiddleware::new(handler)),
|
handler: Arc::new(RpcMiddleware::new(handler)),
|
||||||
panic_handler: panic_handler,
|
panic_handler: panic_handler,
|
||||||
cors_domain: None,
|
cors_domain: Some(cors_domains.into_iter().map(AccessControlAllowOrigin::Value).collect()),
|
||||||
// NOTE [ToDr] We don't need to do any hosts validation here. It's already done in router.
|
// NOTE [ToDr] We don't need to do any hosts validation here. It's already done in router.
|
||||||
allowed_hosts: None,
|
allowed_hosts: None,
|
||||||
})
|
})
|
||||||
@ -60,7 +64,12 @@ impl RpcMiddleware {
|
|||||||
fn new(handler: Arc<IoHandler>) -> Self {
|
fn new(handler: Arc<IoHandler>) -> Self {
|
||||||
RpcMiddleware {
|
RpcMiddleware {
|
||||||
handler: handler,
|
handler: handler,
|
||||||
methods: vec!["eth_accounts".into(), "parity_accountsInfo".into()],
|
methods: vec![
|
||||||
|
"eth_accounts".into(),
|
||||||
|
"eth_coinbase".into(),
|
||||||
|
"parity_accountsInfo".into(),
|
||||||
|
"parity_defaultAccount".into(),
|
||||||
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +68,7 @@ impl<F: Fetch> Endpoint for Web<F> {
|
|||||||
|
|
||||||
struct WebInstaller {
|
struct WebInstaller {
|
||||||
embeddable_on: Embeddable,
|
embeddable_on: Embeddable,
|
||||||
|
referer: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContentValidator for WebInstaller {
|
impl ContentValidator for WebInstaller {
|
||||||
@ -84,7 +85,12 @@ impl ContentValidator for WebInstaller {
|
|||||||
self.embeddable_on.clone(),
|
self.embeddable_on.clone(),
|
||||||
);
|
);
|
||||||
if is_html {
|
if is_html {
|
||||||
handler.set_initial_content(&format!(r#"<script src="/{}/inject.js"></script>"#, apps::UTILS_PATH));
|
handler.set_initial_content(&format!(
|
||||||
|
r#"<script src="/{}/inject.js"></script><script>history.replaceState({{}}, "", "/?{}{}")</script>"#,
|
||||||
|
apps::UTILS_PATH,
|
||||||
|
apps::URL_REFERER,
|
||||||
|
&self.referer,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Ok(ValidatorResponse::Streaming(handler))
|
Ok(ValidatorResponse::Streaming(handler))
|
||||||
}
|
}
|
||||||
@ -108,7 +114,7 @@ struct WebHandler<F: Fetch> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Fetch> WebHandler<F> {
|
impl<F: Fetch> WebHandler<F> {
|
||||||
fn extract_target_url(&self, url: Option<Url>) -> Result<String, State<F>> {
|
fn extract_target_url(&self, url: Option<Url>) -> Result<(String, String), State<F>> {
|
||||||
let (path, query) = match url {
|
let (path, query) = match url {
|
||||||
Some(url) => (url.path, url.query),
|
Some(url) => (url.path, url.query),
|
||||||
None => {
|
None => {
|
||||||
@ -157,7 +163,7 @@ impl<F: Fetch> WebHandler<F> {
|
|||||||
None => "".into(),
|
None => "".into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(format!("{}://{}{}", protocol, path[idx + 2..].join("/"), query))
|
Ok((format!("{}://{}{}", protocol, path[idx + 2..].join("/"), query), path[0..].join("/")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +172,7 @@ impl<F: Fetch> server::Handler<net::HttpStream> for WebHandler<F> {
|
|||||||
let url = extract_url(&request);
|
let url = extract_url(&request);
|
||||||
|
|
||||||
// First extract the URL (reject invalid URLs)
|
// First extract the URL (reject invalid URLs)
|
||||||
let target_url = match self.extract_target_url(url) {
|
let (target_url, referer) = match self.extract_target_url(url) {
|
||||||
Ok(url) => url,
|
Ok(url) => url,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
self.state = error;
|
self.state = error;
|
||||||
@ -180,6 +186,7 @@ impl<F: Fetch> server::Handler<net::HttpStream> for WebHandler<F> {
|
|||||||
self.control.clone(),
|
self.control.clone(),
|
||||||
WebInstaller {
|
WebInstaller {
|
||||||
embeddable_on: self.embeddable_on.clone(),
|
embeddable_on: self.embeddable_on.clone(),
|
||||||
|
referer: referer,
|
||||||
},
|
},
|
||||||
self.embeddable_on.clone(),
|
self.embeddable_on.clone(),
|
||||||
self.remote.clone(),
|
self.remote.clone(),
|
||||||
|
@ -11,7 +11,7 @@ rustc_version = "0.1"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
parity-ui-dev = { path = "../../js", optional = true }
|
parity-ui-dev = { path = "../../js", optional = true }
|
||||||
parity-ui-precompiled = { git = "https://github.com/ethcore/js-precompiled.git", optional = true }
|
parity-ui-precompiled = { git = "https://github.com/ethcore/js-precompiled.git", branch = "stable", optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
no-precompiled-js = ["parity-ui-dev"]
|
no-precompiled-js = ["parity-ui-dev"]
|
||||||
|
83
docker/hub/Dockerfile
Normal file
83
docker/hub/Dockerfile
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
FROM ubuntu:14.04
|
||||||
|
MAINTAINER Parity Technologies <devops@parity.io>
|
||||||
|
WORKDIR /build
|
||||||
|
#ENV for build TAG
|
||||||
|
ARG BUILD_TAG
|
||||||
|
ENV BUILD_TAG ${BUILD_TAG:-master}
|
||||||
|
RUN echo $BUILD_TAG
|
||||||
|
# install tools and dependencies
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --force-yes --no-install-recommends \
|
||||||
|
# make
|
||||||
|
build-essential \
|
||||||
|
# add-apt-repository
|
||||||
|
software-properties-common \
|
||||||
|
make \
|
||||||
|
curl \
|
||||||
|
wget \
|
||||||
|
git \
|
||||||
|
g++ \
|
||||||
|
gcc \
|
||||||
|
libc6 \
|
||||||
|
libc6-dev \
|
||||||
|
binutils \
|
||||||
|
file \
|
||||||
|
openssl \
|
||||||
|
libssl-dev \
|
||||||
|
libudev-dev \
|
||||||
|
pkg-config \
|
||||||
|
dpkg-dev \
|
||||||
|
# evmjit dependencies
|
||||||
|
zlib1g-dev \
|
||||||
|
libedit-dev \
|
||||||
|
libudev-dev &&\
|
||||||
|
# cmake and llvm ppa's. then update ppa's
|
||||||
|
add-apt-repository -y "ppa:george-edison55/cmake-3.x" && \
|
||||||
|
add-apt-repository "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main" && \
|
||||||
|
apt-get update && \
|
||||||
|
apt-get install -y --force-yes cmake llvm-3.7-dev && \
|
||||||
|
# install evmjit
|
||||||
|
git clone https://github.com/debris/evmjit && \
|
||||||
|
cd evmjit && \
|
||||||
|
mkdir build && cd build && \
|
||||||
|
cmake .. && make && make install && cd && \
|
||||||
|
# install rustup
|
||||||
|
curl https://sh.rustup.rs -sSf | sh -s -- -y && \
|
||||||
|
# rustup directory
|
||||||
|
PATH=/root/.cargo/bin:$PATH && \
|
||||||
|
# show backtraces
|
||||||
|
RUST_BACKTRACE=1 && \
|
||||||
|
# build parity
|
||||||
|
cd /build&&git clone https://github.com/ethcore/parity && \
|
||||||
|
cd parity && \
|
||||||
|
git pull&& \
|
||||||
|
git checkout $BUILD_TAG && \
|
||||||
|
cargo build --verbose --release --features final && \
|
||||||
|
#ls /build/parity/target/release/parity && \
|
||||||
|
strip /build/parity/target/release/parity && \
|
||||||
|
file /build/parity/target/release/parity&&mkdir -p /parity&& cp /build/parity/target/release/parity /parity&&\
|
||||||
|
#cleanup Docker image
|
||||||
|
rm -rf /root/.cargo&&rm -rf /root/.multirust&&rm -rf /root/.rustup&&rm -rf /build&&\
|
||||||
|
apt-get purge -y \
|
||||||
|
# make
|
||||||
|
build-essential \
|
||||||
|
# add-apt-repository
|
||||||
|
software-properties-common \
|
||||||
|
make \
|
||||||
|
curl \
|
||||||
|
wget \
|
||||||
|
git \
|
||||||
|
g++ \
|
||||||
|
gcc \
|
||||||
|
binutils \
|
||||||
|
file \
|
||||||
|
pkg-config \
|
||||||
|
dpkg-dev \
|
||||||
|
# evmjit dependencies
|
||||||
|
zlib1g-dev \
|
||||||
|
libedit-dev \
|
||||||
|
cmake llvm-3.7-dev&&\
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
# setup ENTRYPOINT
|
||||||
|
EXPOSE 8080 8545 8180
|
||||||
|
ENTRYPOINT ["/parity/parity"]
|
@ -1,14 +1,19 @@
|
|||||||
FROM ubuntu:14.04
|
FROM ubuntu:14.04
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
# install tools and dependencies
|
# install tools and dependencies
|
||||||
RUN apt-get update && \
|
RUN apt-get -y update && \
|
||||||
apt-get install -y \
|
apt-get install -y --force-yes --no-install-recommends g++ gcc libc6 libc6-dev \
|
||||||
g++ \
|
python binutils curl git make file ca-certificates zip dpkg-dev rhash openssl build-essential pkg-config libssl-dev
|
||||||
build-essential \
|
|
||||||
curl \
|
# install AWS CLI
|
||||||
git \
|
RUN curl -O https://bootstrap.pypa.io/get-pip.py && \
|
||||||
file \
|
python get-pip.py && \
|
||||||
binutils
|
pip install awscli
|
||||||
|
|
||||||
|
# install nodejs
|
||||||
|
RUN curl -sL https://deb.nodesource.com/setup_6.x | bash - && \
|
||||||
|
apt-get install -y nodejs && \
|
||||||
|
apt-get clean
|
||||||
|
|
||||||
# install rustup
|
# install rustup
|
||||||
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
|
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
|
||||||
@ -30,7 +35,7 @@ RUN git clone https://github.com/ethcore/parity && \
|
|||||||
cd parity && \
|
cd parity && \
|
||||||
git checkout beta && \
|
git checkout beta && \
|
||||||
git pull && \
|
git pull && \
|
||||||
cargo build --release --verbose && \
|
cargo build --features final --release --verbose && \
|
||||||
ls /build/parity/target/release/parity && \
|
ls /build/parity/target/release/parity && \
|
||||||
strip /build/parity/target/release/parity
|
strip /build/parity/target/release/parity
|
||||||
|
|
||||||
|
@ -197,6 +197,7 @@ impl HeaderChain {
|
|||||||
pub fn get_header(&self, id: BlockId) -> Option<Bytes> {
|
pub fn get_header(&self, id: BlockId) -> Option<Bytes> {
|
||||||
match id {
|
match id {
|
||||||
BlockId::Earliest | BlockId::Number(0) => Some(self.genesis_header.clone()),
|
BlockId::Earliest | BlockId::Number(0) => Some(self.genesis_header.clone()),
|
||||||
|
BlockId::Latest if self.headers.read().is_empty() => Some(self.genesis_header.clone()),
|
||||||
BlockId::Hash(hash) => self.headers.read().get(&hash).map(|x| x.to_vec()),
|
BlockId::Hash(hash) => self.headers.read().get(&hash).map(|x| x.to_vec()),
|
||||||
BlockId::Number(num) => {
|
BlockId::Number(num) => {
|
||||||
if self.best_block.read().number < num { return None }
|
if self.best_block.read().number < num { return None }
|
||||||
|
@ -21,8 +21,9 @@ use ethcore::block_status::BlockStatus;
|
|||||||
use ethcore::client::ClientReport;
|
use ethcore::client::ClientReport;
|
||||||
use ethcore::ids::BlockId;
|
use ethcore::ids::BlockId;
|
||||||
use ethcore::header::Header;
|
use ethcore::header::Header;
|
||||||
|
use ethcore::views::HeaderView;
|
||||||
use ethcore::verification::queue::{self, HeaderQueue};
|
use ethcore::verification::queue::{self, HeaderQueue};
|
||||||
use ethcore::transaction::PendingTransaction;
|
use ethcore::transaction::{PendingTransaction, Condition as TransactionCondition};
|
||||||
use ethcore::blockchain_info::BlockChainInfo;
|
use ethcore::blockchain_info::BlockChainInfo;
|
||||||
use ethcore::spec::Spec;
|
use ethcore::spec::Spec;
|
||||||
use ethcore::service::ClientIoMessage;
|
use ethcore::service::ClientIoMessage;
|
||||||
@ -34,6 +35,7 @@ use util::{Bytes, Mutex, RwLock};
|
|||||||
|
|
||||||
use provider::Provider;
|
use provider::Provider;
|
||||||
use request;
|
use request;
|
||||||
|
use time;
|
||||||
|
|
||||||
use self::header_chain::HeaderChain;
|
use self::header_chain::HeaderChain;
|
||||||
|
|
||||||
@ -109,7 +111,11 @@ impl Client {
|
|||||||
let best_num = self.chain.best_block().number;
|
let best_num = self.chain.best_block().number;
|
||||||
self.tx_pool.lock()
|
self.tx_pool.lock()
|
||||||
.values()
|
.values()
|
||||||
.filter(|t| t.min_block.as_ref().map_or(true, |x| x <= &best_num))
|
.filter(|t| match t.condition {
|
||||||
|
Some(TransactionCondition::Number(ref x)) => x <= &best_num,
|
||||||
|
Some(TransactionCondition::Timestamp(ref x)) => *x <= time::get_time().sec as u64,
|
||||||
|
None => true,
|
||||||
|
})
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
@ -134,6 +140,7 @@ impl Client {
|
|||||||
genesis_hash: genesis_hash,
|
genesis_hash: genesis_hash,
|
||||||
best_block_hash: best_block.hash,
|
best_block_hash: best_block.hash,
|
||||||
best_block_number: best_block.number,
|
best_block_number: best_block.number,
|
||||||
|
best_block_timestamp: HeaderView::new(&self.chain.get_header(BlockId::Latest).expect("Latest hash is always in the chain")).timestamp(),
|
||||||
ancient_block_hash: if first_block.is_some() { Some(genesis_hash) } else { None },
|
ancient_block_hash: if first_block.is_some() { Some(genesis_hash) } else { None },
|
||||||
ancient_block_number: if first_block.is_some() { Some(0) } else { None },
|
ancient_block_number: if first_block.is_some() { Some(0) } else { None },
|
||||||
first_block_hash: first_block.as_ref().map(|first| first.hash),
|
first_block_hash: first_block.as_ref().map(|first| first.hash),
|
||||||
|
@ -47,18 +47,12 @@
|
|||||||
"stateRoot": "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544"
|
"stateRoot": "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544"
|
||||||
},
|
},
|
||||||
"nodes": [
|
"nodes": [
|
||||||
"enode://08c7ee6a4f861ff0664a49532bcc86de1363acd608999d1b76609bb9bc278649906f069057630fd9493924a368b5d1dc9b8f8bf13ac26df72512f6d1fabd8c95@45.32.7.81:30303",
|
|
||||||
"enode://e809c4a2fec7daed400e5e28564e23693b23b2cc5a019b612505631bbe7b9ccf709c1796d2a3d29ef2b045f210caf51e3c4f5b6d3587d43ad5d6397526fa6179@174.112.32.157:30303",
|
"enode://e809c4a2fec7daed400e5e28564e23693b23b2cc5a019b612505631bbe7b9ccf709c1796d2a3d29ef2b045f210caf51e3c4f5b6d3587d43ad5d6397526fa6179@174.112.32.157:30303",
|
||||||
"enode://687be94c3a7beaa3d2fde82fa5046cdeb3e8198354e05b29d6e0d4e276713e3707ac10f784a7904938b06b46c764875c241b0337dd853385a4d8bfcbf8190647@95.183.51.229:30303",
|
|
||||||
"enode://6e538e7c1280f0a31ff08b382db5302480f775480b8e68f8febca0ceff81e4b19153c6f8bf60313b93bef2cc34d34e1df41317de0ce613a201d1660a788a03e2@52.206.67.235:30303",
|
"enode://6e538e7c1280f0a31ff08b382db5302480f775480b8e68f8febca0ceff81e4b19153c6f8bf60313b93bef2cc34d34e1df41317de0ce613a201d1660a788a03e2@52.206.67.235:30303",
|
||||||
"enode://ca5ae4eca09ba6787e29cf6d86f7634d07aae6b9e6317a59aff675851c0bf445068173208cf8ef7f5cd783d8e29b85b2fa3fa358124cf0546823149724f9bde1@138.68.1.16:30303",
|
"enode://5fbfb426fbb46f8b8c1bd3dd140f5b511da558cd37d60844b525909ab82e13a25ee722293c829e52cb65c2305b1637fa9a2ea4d6634a224d5f400bfe244ac0de@162.243.55.45:30303",
|
||||||
"enode://217ebe27e89bf4fec8ce06509323ff095b1014378deb75ab2e5f6759a4e8750a3bd8254b8c6833136e4d5e58230d65ee8ab34a5db5abf0640408c4288af3c8a7@188.138.1.237:30303",
|
"enode://42d8f29d1db5f4b2947cd5c3d76c6d0d3697e6b9b3430c3d41e46b4bb77655433aeedc25d4b4ea9d8214b6a43008ba67199374a9b53633301bca0cd20c6928ab@104.155.176.151:30303",
|
||||||
"enode://fa20444ef991596ce99b81652ac4e61de1eddc4ff21d3cd42762abd7ed47e7cf044d3c9ccddaf6035d39725e4eb372806787829ccb9a08ec7cb71883cb8c3abd@50.149.116.182:30303",
|
"enode://814920f1ec9510aa9ea1c8f79d8b6e6a462045f09caa2ae4055b0f34f7416fca6facd3dd45f1cf1673c0209e0503f02776b8ff94020e98b6679a0dc561b4eba0@104.154.136.117:30303",
|
||||||
"enode://4bd6a4df3612c718333eb5ea7f817923a8cdf1bed89cee70d1710b45a0b6b77b2819846440555e451a9b602ad2efa2d2facd4620650249d8468008946887820a@71.178.232.20:30304",
|
"enode://72e445f4e89c0f476d404bc40478b0df83a5b500d2d2e850e08eb1af0cd464ab86db6160d0fde64bd77d5f0d33507ae19035671b3c74fec126d6e28787669740@104.198.71.200:30303"
|
||||||
"enode://921cf8e4c345fe8db913c53964f9cadc667644e7f20195a0b7d877bd689a5934e146ff2c2259f1bae6817b6585153a007ceb67d260b720fa3e6fc4350df25c7f@51.255.49.170:30303",
|
|
||||||
"enode://ffea3b01c000cdd89e1e9229fea3e80e95b646f9b2aa55071fc865e2f19543c9b06045cc2e69453e6b78100a119e66be1b5ad50b36f2ffd27293caa28efdd1b2@128.199.93.177:3030",
|
|
||||||
"enode://ee3da491ce6a155eb132708eb0e8d04b0637926ec0ae1b79e63fc97cb9fc3818f49250a0ae0d7f79ed62b66ec677f408c4e01741504dc7a051e274f1e803d454@91.121.65.179:40404",
|
|
||||||
"enode://48e063a6cf5f335b1ef2ed98126bf522cf254396f850c7d442fe2edbbc23398787e14cd4de7968a00175a82762de9cbe9e1407d8ccbcaeca5004d65f8398d759@159.203.255.59:30303"
|
|
||||||
],
|
],
|
||||||
"accounts": {
|
"accounts": {
|
||||||
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "Frontier/Homestead",
|
"name": "Foundation",
|
||||||
"dataDir": "ethereum",
|
"dataDir": "ethereum",
|
||||||
"engine": {
|
"engine": {
|
||||||
"Ethash": {
|
"Ethash": {
|
||||||
@ -9,7 +9,7 @@
|
|||||||
"difficultyBoundDivisor": "0x0800",
|
"difficultyBoundDivisor": "0x0800",
|
||||||
"durationLimit": "0x0d",
|
"durationLimit": "0x0d",
|
||||||
"blockReward": "0x4563918244F40000",
|
"blockReward": "0x4563918244F40000",
|
||||||
"registrar" : "0x3bb2bb5c6c9c9b7f4ef430b47dc7e026310042ea",
|
"registrar" : "0xe3389675d0338462dC76C6f9A3e432550c36A142",
|
||||||
"homesteadTransition": "0x118c30",
|
"homesteadTransition": "0x118c30",
|
||||||
"daoHardforkTransition": "0x1d4c00",
|
"daoHardforkTransition": "0x1d4c00",
|
||||||
"daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754",
|
"daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754",
|
59
ethcore/res/ethereum/kovan.json
Normal file
59
ethcore/res/ethereum/kovan.json
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"name": "Kovan",
|
||||||
|
"dataDir": "kovan",
|
||||||
|
"engine": {
|
||||||
|
"authorityRound": {
|
||||||
|
"params": {
|
||||||
|
"gasLimitBoundDivisor": "0x400",
|
||||||
|
"registrar" : "0xfAb104398BBefbd47752E7702D9fE23047E1Bca3",
|
||||||
|
"stepDuration": "4",
|
||||||
|
"blockReward": "0x4563918244F40000",
|
||||||
|
"validators" : {
|
||||||
|
"list": [
|
||||||
|
"0x00D6Cc1BA9cf89BD2e58009741f4F7325BAdc0ED",
|
||||||
|
"0x00427feae2419c15b89d1c21af10d1b6650a4d3d",
|
||||||
|
"0x4Ed9B08e6354C70fE6F8CB0411b0d3246b424d6c",
|
||||||
|
"0x0020ee4Be0e2027d76603cB751eE069519bA81A1",
|
||||||
|
|
||||||
|
"0x0010f94b296a852aaac52ea6c5ac72e03afd032d",
|
||||||
|
|
||||||
|
"0x007733a1FE69CF3f2CF989F81C7b4cAc1693387A",
|
||||||
|
"0x00E6d2b931F55a3f1701c7389d592a7778897879",
|
||||||
|
"0x00e4a10650e5a6D6001C38ff8E64F97016a1645c",
|
||||||
|
|
||||||
|
"0x00a0a24b9f0e5ec7aa4c7389b8302fd0123194de"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"maximumExtraDataSize": "0x20",
|
||||||
|
"minGasLimit": "0x1388",
|
||||||
|
"networkID" : "0x2A"
|
||||||
|
},
|
||||||
|
"genesis": {
|
||||||
|
"seal": {
|
||||||
|
"authorityRound": {
|
||||||
|
"step": "0x0",
|
||||||
|
"signature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"difficulty": "0x20000",
|
||||||
|
"gasLimit": "0x5B8D80"
|
||||||
|
},
|
||||||
|
"accounts": {
|
||||||
|
"0x0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||||
|
"0x0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||||
|
"0x0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||||
|
"0x0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
|
||||||
|
"0x00521965e7bd230323c423d96c657db5b79d099f": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }
|
||||||
|
},
|
||||||
|
"nodes": [
|
||||||
|
"enode://c005dd308256c60fab247813d8bf6d6e81f9cd354287837eb1c2fcf294adaa913a3208e88900ef5c55a8cba7042c301d80503edec2ad3f92a72e241ee6743854@192.241.230.87:30303",
|
||||||
|
"enode://48caeceb2724f2f71406990aa81efe87f8c53f26441d891473da2ae50cc138f238addc0e46b5aee240db55de8c711daac53d7b32a3f13e30edb86a3ca7c2700b@138.68.143.220:30303",
|
||||||
|
"enode://85705212fd28ebdd56669fb55e958feb9d81f74fe76c82f867564b6c2995e69f596df0f588eba16f1a43b69ce06485d68231a0c83fed8469b41eba0e390c126f@139.59.146.42:30303",
|
||||||
|
"enode://2aa81bd0a761cd4f02c934dcf3f81c5b65953e51ab5ba03ceb1f125eb06418a1cdffb1c9d01871aa7bd456f3fce35e745608189ad1164f72b2161634b0c3f6ea@188.166.240.190:30303",
|
||||||
|
"enode://c5900cdd6d20795d58372f42dfbab9d664c27bb97e9c27972741942736e919122f9bac28e74cbc58e4ff195475ea90d9880b71a37af5b5a8cb41d843f765cff8@174.138.79.48:30303"
|
||||||
|
]
|
||||||
|
}
|
@ -47,7 +47,10 @@
|
|||||||
},
|
},
|
||||||
"nodes": [
|
"nodes": [
|
||||||
"enode://e731347db0521f3476e6bbbb83375dcd7133a1601425ebd15fd10f3835fd4c304fba6282087ca5a0deeafadf0aa0d4fd56c3323331901c1f38bd181c283e3e35@128.199.55.137:30303",
|
"enode://e731347db0521f3476e6bbbb83375dcd7133a1601425ebd15fd10f3835fd4c304fba6282087ca5a0deeafadf0aa0d4fd56c3323331901c1f38bd181c283e3e35@128.199.55.137:30303",
|
||||||
"enode://ceb5c0f85eb994dbe9693bf46d99b03f6b838d17cc74e68d5eb003171ff39e5f120b17f965b267c319303f94d80b9d994b77062fb1486d76ce95d9f3d8fe1cb4@46.101.122.141:30303"
|
"enode://ceb5c0f85eb994dbe9693bf46d99b03f6b838d17cc74e68d5eb003171ff39e5f120b17f965b267c319303f94d80b9d994b77062fb1486d76ce95d9f3d8fe1cb4@46.101.122.141:30303",
|
||||||
|
"enode://fb28713820e718066a2f5df6250ae9d07cff22f672dbf26be6c75d088f821a9ad230138ba492c533a80407d054b1436ef18e951bb65e6901553516c8dffe8ff0@104.155.176.151:30304",
|
||||||
|
"enode://afdc6076b9bf3e7d3d01442d6841071e84c76c73a7016cb4f35c0437df219db38565766234448f1592a07ba5295a867f0ce87b359bf50311ed0b830a2361392d@104.154.136.117:30403",
|
||||||
|
"enode://21101a9597b79e933e17bc94ef3506fe99a137808907aa8fefa67eea4b789792ad11fb391f38b00087f8800a2d3dff011572b62a31232133dd1591ac2d1502c8@104.198.71.200:30403"
|
||||||
],
|
],
|
||||||
"accounts": {
|
"accounts": {
|
||||||
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||||
|
@ -24,7 +24,9 @@
|
|||||||
"accountStartNonce": "0x0",
|
"accountStartNonce": "0x0",
|
||||||
"maximumExtraDataSize": "0x20",
|
"maximumExtraDataSize": "0x20",
|
||||||
"minGasLimit": "0x1388",
|
"minGasLimit": "0x1388",
|
||||||
"networkID" : "0x3"
|
"networkID" : "0x3",
|
||||||
|
"forkBlock": 333922,
|
||||||
|
"forkCanonHash": "0x8737eb141d4f05db57af63fc8d3b4d4d8f9cddb0c4e1ab855de8c288fdc1924f"
|
||||||
},
|
},
|
||||||
"genesis": {
|
"genesis": {
|
||||||
"seal": {
|
"seal": {
|
||||||
@ -42,7 +44,10 @@
|
|||||||
},
|
},
|
||||||
"nodes": [
|
"nodes": [
|
||||||
"enode://a22f0977ce02653bf95e38730106356342df48b5222e2c2a1a6f9ef34769bf593bae9ca0a888cf60839edd52efc1b6e393c63a57d76f4c4fe14e641f1f9e637e@128.199.55.137:30303",
|
"enode://a22f0977ce02653bf95e38730106356342df48b5222e2c2a1a6f9ef34769bf593bae9ca0a888cf60839edd52efc1b6e393c63a57d76f4c4fe14e641f1f9e637e@128.199.55.137:30303",
|
||||||
"enode://012239fccf3ff1d92b036983a430cb6705c6528c96c0354413f8854802138e5135c084ab36e7c54efb621c46728df8c3a6f4c1db9bb48a1330efe3f82f2dd7a6@52.169.94.142:30303"
|
"enode://012239fccf3ff1d92b036983a430cb6705c6528c96c0354413f8854802138e5135c084ab36e7c54efb621c46728df8c3a6f4c1db9bb48a1330efe3f82f2dd7a6@52.169.94.142:30303",
|
||||||
|
"enode://1462682e4b7ba2258346d55e25e5b9d264b0db40cee12bdfba4e72b1d7050350ea954c006e9106dd96a128e6e0bd6dffb17eed51f9f99bf7f9cdadfeaf8da4ff@51.15.61.253:30303",
|
||||||
|
"enode://98fbb020c799ae39a828bd75dc2bd5d4721539faf317076b275f91182a5c8900b592e8abfdddceae674a7c3bb40ea00a6ca9ccb7805ab58c4b7b29c61c8f7239@51.15.62.44:30303",
|
||||||
|
"enode://d801dd4e3d15a8bf785931add164bd9c313e3f6b5749d9302b311f2b48064cba5c86c32b1302c27cd983fc89ae07d4d306dd1197610835b8782e95dfb1b3f9ea@51.15.43.255:30303"
|
||||||
],
|
],
|
||||||
"accounts": {
|
"accounts": {
|
||||||
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "0", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "0", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||||
|
File diff suppressed because one or more lines are too long
@ -24,6 +24,8 @@ pub struct BestBlock {
|
|||||||
pub hash: H256,
|
pub hash: H256,
|
||||||
/// Best block number.
|
/// Best block number.
|
||||||
pub number: BlockNumber,
|
pub number: BlockNumber,
|
||||||
|
/// Best block timestamp.
|
||||||
|
pub timestamp: u64,
|
||||||
/// Best block total difficulty.
|
/// Best block total difficulty.
|
||||||
pub total_difficulty: U256,
|
pub total_difficulty: U256,
|
||||||
/// Best block uncompressed bytes
|
/// Best block uncompressed bytes
|
||||||
|
@ -490,6 +490,7 @@ impl BlockChain {
|
|||||||
let best_block_number = bc.block_number(&best_block_hash).unwrap();
|
let best_block_number = bc.block_number(&best_block_hash).unwrap();
|
||||||
let best_block_total_difficulty = bc.block_details(&best_block_hash).unwrap().total_difficulty;
|
let best_block_total_difficulty = bc.block_details(&best_block_hash).unwrap().total_difficulty;
|
||||||
let best_block_rlp = bc.block(&best_block_hash).unwrap().into_inner();
|
let best_block_rlp = bc.block(&best_block_hash).unwrap().into_inner();
|
||||||
|
let best_block_timestamp = BlockView::new(&best_block_rlp).header().timestamp();
|
||||||
|
|
||||||
let raw_first = bc.db.get(db::COL_EXTRA, b"first").unwrap().map(|v| v.to_vec());
|
let raw_first = bc.db.get(db::COL_EXTRA, b"first").unwrap().map(|v| v.to_vec());
|
||||||
let mut best_ancient = bc.db.get(db::COL_EXTRA, b"ancient").unwrap().map(|h| H256::from_slice(&h));
|
let mut best_ancient = bc.db.get(db::COL_EXTRA, b"ancient").unwrap().map(|h| H256::from_slice(&h));
|
||||||
@ -538,6 +539,7 @@ impl BlockChain {
|
|||||||
number: best_block_number,
|
number: best_block_number,
|
||||||
total_difficulty: best_block_total_difficulty,
|
total_difficulty: best_block_total_difficulty,
|
||||||
hash: best_block_hash,
|
hash: best_block_hash,
|
||||||
|
timestamp: best_block_timestamp,
|
||||||
block: best_block_rlp,
|
block: best_block_rlp,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -590,6 +592,7 @@ impl BlockChain {
|
|||||||
number: extras.number - 1,
|
number: extras.number - 1,
|
||||||
total_difficulty: best_block_total_difficulty,
|
total_difficulty: best_block_total_difficulty,
|
||||||
hash: hash,
|
hash: hash,
|
||||||
|
timestamp: BlockView::new(&best_block_rlp).header().timestamp(),
|
||||||
block: best_block_rlp,
|
block: best_block_rlp,
|
||||||
};
|
};
|
||||||
// update parent extras
|
// update parent extras
|
||||||
@ -743,6 +746,7 @@ impl BlockChain {
|
|||||||
blocks_blooms: self.prepare_block_blooms_update(bytes, &info),
|
blocks_blooms: self.prepare_block_blooms_update(bytes, &info),
|
||||||
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
|
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
|
||||||
info: info,
|
info: info,
|
||||||
|
timestamp: header.timestamp(),
|
||||||
block: bytes
|
block: bytes
|
||||||
}, is_best);
|
}, is_best);
|
||||||
|
|
||||||
@ -791,6 +795,7 @@ impl BlockChain {
|
|||||||
blocks_blooms: self.prepare_block_blooms_update(bytes, &info),
|
blocks_blooms: self.prepare_block_blooms_update(bytes, &info),
|
||||||
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
|
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
|
||||||
info: info,
|
info: info,
|
||||||
|
timestamp: header.timestamp(),
|
||||||
block: bytes,
|
block: bytes,
|
||||||
}, is_best);
|
}, is_best);
|
||||||
true
|
true
|
||||||
@ -855,6 +860,7 @@ impl BlockChain {
|
|||||||
blocks_blooms: self.prepare_block_blooms_update(bytes, &info),
|
blocks_blooms: self.prepare_block_blooms_update(bytes, &info),
|
||||||
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
|
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
|
||||||
info: info.clone(),
|
info: info.clone(),
|
||||||
|
timestamp: header.timestamp(),
|
||||||
block: bytes,
|
block: bytes,
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
@ -926,6 +932,7 @@ impl BlockChain {
|
|||||||
hash: update.info.hash,
|
hash: update.info.hash,
|
||||||
number: update.info.number,
|
number: update.info.number,
|
||||||
total_difficulty: update.info.total_difficulty,
|
total_difficulty: update.info.total_difficulty,
|
||||||
|
timestamp: update.timestamp,
|
||||||
block: update.block.to_vec(),
|
block: update.block.to_vec(),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -1211,6 +1218,11 @@ impl BlockChain {
|
|||||||
self.best_block.read().number
|
self.best_block.read().number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get best block timestamp.
|
||||||
|
pub fn best_block_timestamp(&self) -> u64 {
|
||||||
|
self.best_block.read().timestamp
|
||||||
|
}
|
||||||
|
|
||||||
/// Get best block total difficulty.
|
/// Get best block total difficulty.
|
||||||
pub fn best_block_total_difficulty(&self) -> U256 {
|
pub fn best_block_total_difficulty(&self) -> U256 {
|
||||||
self.best_block.read().total_difficulty
|
self.best_block.read().total_difficulty
|
||||||
@ -1298,6 +1310,7 @@ impl BlockChain {
|
|||||||
genesis_hash: self.genesis_hash(),
|
genesis_hash: self.genesis_hash(),
|
||||||
best_block_hash: best_block.hash.clone(),
|
best_block_hash: best_block.hash.clone(),
|
||||||
best_block_number: best_block.number,
|
best_block_number: best_block.number,
|
||||||
|
best_block_timestamp: best_block.timestamp,
|
||||||
first_block_hash: self.first_block(),
|
first_block_hash: self.first_block(),
|
||||||
first_block_number: From::from(self.first_block_number()),
|
first_block_number: From::from(self.first_block_number()),
|
||||||
ancient_block_hash: best_ancient_block.as_ref().map(|b| b.hash.clone()),
|
ancient_block_hash: best_ancient_block.as_ref().map(|b| b.hash.clone()),
|
||||||
@ -1329,6 +1342,7 @@ mod tests {
|
|||||||
use transaction::{Transaction, Action};
|
use transaction::{Transaction, Action};
|
||||||
use log_entry::{LogEntry, LocalizedLogEntry};
|
use log_entry::{LogEntry, LocalizedLogEntry};
|
||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
|
use ethkey::Secret;
|
||||||
|
|
||||||
fn new_db(path: &str) -> Arc<Database> {
|
fn new_db(path: &str) -> Arc<Database> {
|
||||||
Arc::new(Database::open(&DatabaseConfig::with_columns(::db::NUM_COLUMNS), path).unwrap())
|
Arc::new(Database::open(&DatabaseConfig::with_columns(::db::NUM_COLUMNS), path).unwrap())
|
||||||
@ -1467,6 +1481,10 @@ mod tests {
|
|||||||
// TODO: insert block that already includes one of them as an uncle to check it's not allowed.
|
// TODO: insert block that already includes one of them as an uncle to check it's not allowed.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn secret() -> Secret {
|
||||||
|
Secret::from_slice(&"".sha3()).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fork_transaction_addresses() {
|
fn test_fork_transaction_addresses() {
|
||||||
let mut canon_chain = ChainGenerator::default();
|
let mut canon_chain = ChainGenerator::default();
|
||||||
@ -1482,7 +1500,7 @@ mod tests {
|
|||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
|
|
||||||
let b1a = canon_chain
|
let b1a = canon_chain
|
||||||
@ -1546,7 +1564,7 @@ mod tests {
|
|||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
let t2 = Transaction {
|
let t2 = Transaction {
|
||||||
nonce: 1.into(),
|
nonce: 1.into(),
|
||||||
@ -1555,7 +1573,7 @@ mod tests {
|
|||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
let t3 = Transaction {
|
let t3 = Transaction {
|
||||||
nonce: 2.into(),
|
nonce: 2.into(),
|
||||||
@ -1564,7 +1582,7 @@ mod tests {
|
|||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
let b1a = canon_chain
|
let b1a = canon_chain
|
||||||
.with_transaction(t1.clone())
|
.with_transaction(t1.clone())
|
||||||
@ -1870,7 +1888,7 @@ mod tests {
|
|||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: 101.into(),
|
value: 101.into(),
|
||||||
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
let t2 = Transaction {
|
let t2 = Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
@ -1878,7 +1896,7 @@ mod tests {
|
|||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: 102.into(),
|
value: 102.into(),
|
||||||
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
let t3 = Transaction {
|
let t3 = Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
@ -1886,7 +1904,7 @@ mod tests {
|
|||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: 103.into(),
|
value: 103.into(),
|
||||||
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
let tx_hash1 = t1.hash();
|
let tx_hash1 = t1.hash();
|
||||||
let tx_hash2 = t2.hash();
|
let tx_hash2 = t2.hash();
|
||||||
let tx_hash3 = t3.hash();
|
let tx_hash3 = t3.hash();
|
||||||
|
@ -9,6 +9,8 @@ use super::extras::{BlockDetails, BlockReceipts, TransactionAddress, LogGroupPos
|
|||||||
pub struct ExtrasUpdate<'a> {
|
pub struct ExtrasUpdate<'a> {
|
||||||
/// Block info.
|
/// Block info.
|
||||||
pub info: BlockInfo,
|
pub info: BlockInfo,
|
||||||
|
/// Block timestamp.
|
||||||
|
pub timestamp: u64,
|
||||||
/// Current block uncompressed rlp bytes
|
/// Current block uncompressed rlp bytes
|
||||||
pub block: &'a [u8],
|
pub block: &'a [u8],
|
||||||
/// Modified block hashes.
|
/// Modified block hashes.
|
||||||
|
@ -873,6 +873,83 @@ impl BlockChainClient for Client {
|
|||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn estimate_gas(&self, t: &SignedTransaction, block: BlockId) -> Result<U256, CallError> {
|
||||||
|
const UPPER_CEILING: u64 = 1_000_000_000_000u64;
|
||||||
|
let header = self.block_header(block).ok_or(CallError::StatePruned)?;
|
||||||
|
let last_hashes = self.build_last_hashes(header.parent_hash());
|
||||||
|
let env_info = EnvInfo {
|
||||||
|
number: header.number(),
|
||||||
|
author: header.author(),
|
||||||
|
timestamp: header.timestamp(),
|
||||||
|
difficulty: header.difficulty(),
|
||||||
|
last_hashes: last_hashes,
|
||||||
|
gas_used: U256::zero(),
|
||||||
|
gas_limit: UPPER_CEILING.into(),
|
||||||
|
};
|
||||||
|
// that's just a copy of the state.
|
||||||
|
let original_state = self.state_at(block).ok_or(CallError::StatePruned)?;
|
||||||
|
let sender = t.sender().map_err(|e| {
|
||||||
|
let message = format!("Transaction malformed: {:?}", e);
|
||||||
|
ExecutionError::TransactionMalformed(message)
|
||||||
|
})?;
|
||||||
|
let balance = original_state.balance(&sender);
|
||||||
|
let options = TransactOptions { tracing: true, vm_tracing: false, check_nonce: false };
|
||||||
|
let mut tx = t.clone();
|
||||||
|
|
||||||
|
let mut cond = |gas| {
|
||||||
|
tx.gas = gas;
|
||||||
|
|
||||||
|
let mut state = original_state.clone();
|
||||||
|
let needed_balance = tx.value + tx.gas * tx.gas_price;
|
||||||
|
if balance < needed_balance {
|
||||||
|
// give the sender a sufficient balance
|
||||||
|
state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty);
|
||||||
|
}
|
||||||
|
|
||||||
|
Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm)
|
||||||
|
.transact(&tx, options.clone())
|
||||||
|
.map(|r| r.exception.is_none())
|
||||||
|
.unwrap_or(false)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut upper = header.gas_limit();
|
||||||
|
if !cond(upper) {
|
||||||
|
// impossible at block gas limit - try `UPPER_CEILING` instead.
|
||||||
|
// TODO: consider raising limit by powers of two.
|
||||||
|
upper = UPPER_CEILING.into();
|
||||||
|
if !cond(upper) {
|
||||||
|
trace!(target: "estimate_gas", "estimate_gas failed with {}", upper);
|
||||||
|
return Err(CallError::Execution(ExecutionError::Internal))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let lower = t.gas_required(&self.engine.schedule(&env_info)).into();
|
||||||
|
if cond(lower) {
|
||||||
|
trace!(target: "estimate_gas", "estimate_gas succeeded with {}", lower);
|
||||||
|
return Ok(lower)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find transition point between `lower` and `upper` where `cond` changes from `false` to `true`.
|
||||||
|
/// Returns the lowest value between `lower` and `upper` for which `cond` returns true.
|
||||||
|
/// We assert: `cond(lower) = false`, `cond(upper) = true`
|
||||||
|
fn binary_chop<F>(mut lower: U256, mut upper: U256, mut cond: F) -> U256 where F: FnMut(U256) -> bool {
|
||||||
|
while upper - lower > 1.into() {
|
||||||
|
let mid = (lower + upper) / 2.into();
|
||||||
|
trace!(target: "estimate_gas", "{} .. {} .. {}", lower, mid, upper);
|
||||||
|
let c = cond(mid);
|
||||||
|
match c {
|
||||||
|
true => upper = mid,
|
||||||
|
false => lower = mid,
|
||||||
|
};
|
||||||
|
trace!(target: "estimate_gas", "{} => {} .. {}", c, lower, upper);
|
||||||
|
}
|
||||||
|
upper
|
||||||
|
}
|
||||||
|
|
||||||
|
// binary chop to non-excepting call with gas somewhere between 21000 and block gas limit
|
||||||
|
trace!(target: "estimate_gas", "estimate_gas chopping {} .. {}", lower, upper);
|
||||||
|
Ok(binary_chop(lower, upper, cond))
|
||||||
|
}
|
||||||
|
|
||||||
fn replay(&self, id: TransactionId, analytics: CallAnalytics) -> Result<Executed, CallError> {
|
fn replay(&self, id: TransactionId, analytics: CallAnalytics) -> Result<Executed, CallError> {
|
||||||
let address = self.transaction_address(id).ok_or(CallError::TransactionNotFound)?;
|
let address = self.transaction_address(id).ok_or(CallError::TransactionNotFound)?;
|
||||||
let header = self.block_header(BlockId::Hash(address.block_hash)).ok_or(CallError::StatePruned)?;
|
let header = self.block_header(BlockId::Hash(address.block_hash)).ok_or(CallError::StatePruned)?;
|
||||||
@ -1305,7 +1382,11 @@ impl BlockChainClient for Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn ready_transactions(&self) -> Vec<PendingTransaction> {
|
fn ready_transactions(&self) -> Vec<PendingTransaction> {
|
||||||
self.miner.ready_transactions(self.chain.read().best_block_number())
|
let (number, timestamp) = {
|
||||||
|
let chain = self.chain.read();
|
||||||
|
(chain.best_block_number(), chain.best_block_timestamp())
|
||||||
|
};
|
||||||
|
self.miner.ready_transactions(number, timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn queue_consensus_message(&self, message: Bytes) {
|
fn queue_consensus_message(&self, message: Bytes) {
|
||||||
@ -1594,7 +1675,7 @@ mod tests {
|
|||||||
use util::Hashable;
|
use util::Hashable;
|
||||||
|
|
||||||
// given
|
// given
|
||||||
let key = KeyPair::from_secret("test".sha3()).unwrap();
|
let key = KeyPair::from_secret_slice(&"test".sha3()).unwrap();
|
||||||
let secret = key.secret();
|
let secret = key.secret();
|
||||||
|
|
||||||
let block_number = 1;
|
let block_number = 1;
|
||||||
|
File diff suppressed because one or more lines are too long
@ -242,7 +242,7 @@ impl TestBlockChainClient {
|
|||||||
value: U256::from(100),
|
value: U256::from(100),
|
||||||
data: "3331600055".from_hex().unwrap(),
|
data: "3331600055".from_hex().unwrap(),
|
||||||
gas: U256::from(100_000),
|
gas: U256::from(100_000),
|
||||||
gas_price: U256::one(),
|
gas_price: U256::from(200_000_000_000u64),
|
||||||
nonce: U256::zero()
|
nonce: U256::zero()
|
||||||
};
|
};
|
||||||
let signed_tx = tx.sign(keypair.secret(), None);
|
let signed_tx = tx.sign(keypair.secret(), None);
|
||||||
@ -300,22 +300,29 @@ impl TestBlockChainClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts a transaction to miners transactions queue.
|
/// Inserts a transaction with given gas price to miners transactions queue.
|
||||||
pub fn insert_transaction_to_queue(&self) {
|
pub fn insert_transaction_with_gas_price_to_queue(&self, gas_price: U256) -> H256 {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
let tx = Transaction {
|
let tx = Transaction {
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: U256::from(100),
|
value: U256::from(100),
|
||||||
data: "3331600055".from_hex().unwrap(),
|
data: "3331600055".from_hex().unwrap(),
|
||||||
gas: U256::from(100_000),
|
gas: U256::from(100_000),
|
||||||
gas_price: U256::one(),
|
gas_price: gas_price,
|
||||||
nonce: U256::zero()
|
nonce: U256::zero()
|
||||||
};
|
};
|
||||||
let signed_tx = tx.sign(keypair.secret(), None);
|
let signed_tx = tx.sign(keypair.secret(), None);
|
||||||
self.set_balance(signed_tx.sender().unwrap(), 10_000_000.into());
|
self.set_balance(signed_tx.sender().unwrap(), 10_000_000_000_000_000_000u64.into());
|
||||||
let res = self.miner.import_external_transactions(self, vec![signed_tx]);
|
let hash = signed_tx.hash();
|
||||||
|
let res = self.miner.import_external_transactions(self, vec![signed_tx.into()]);
|
||||||
let res = res.into_iter().next().unwrap().expect("Successful import");
|
let res = res.into_iter().next().unwrap().expect("Successful import");
|
||||||
assert_eq!(res, TransactionImportResult::Current);
|
assert_eq!(res, TransactionImportResult::Current);
|
||||||
|
hash
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inserts a transaction to miners transactions queue.
|
||||||
|
pub fn insert_transaction_to_queue(&self) -> H256 {
|
||||||
|
self.insert_transaction_with_gas_price_to_queue(U256::from(20_000_000_000u64))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set reported history size.
|
/// Set reported history size.
|
||||||
@ -379,6 +386,10 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
self.execution_result.read().clone().unwrap()
|
self.execution_result.read().clone().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn estimate_gas(&self, _t: &SignedTransaction, _block: BlockId) -> Result<U256, CallError> {
|
||||||
|
Ok(21000.into())
|
||||||
|
}
|
||||||
|
|
||||||
fn replay(&self, _id: TransactionId, _analytics: CallAnalytics) -> Result<Executed, CallError> {
|
fn replay(&self, _id: TransactionId, _analytics: CallAnalytics) -> Result<Executed, CallError> {
|
||||||
self.execution_result.read().clone().unwrap()
|
self.execution_result.read().clone().unwrap()
|
||||||
}
|
}
|
||||||
@ -650,12 +661,14 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn chain_info(&self) -> BlockChainInfo {
|
fn chain_info(&self) -> BlockChainInfo {
|
||||||
|
let number = self.blocks.read().len() as BlockNumber - 1;
|
||||||
BlockChainInfo {
|
BlockChainInfo {
|
||||||
total_difficulty: *self.difficulty.read(),
|
total_difficulty: *self.difficulty.read(),
|
||||||
pending_total_difficulty: *self.difficulty.read(),
|
pending_total_difficulty: *self.difficulty.read(),
|
||||||
genesis_hash: self.genesis_hash.clone(),
|
genesis_hash: self.genesis_hash.clone(),
|
||||||
best_block_hash: self.last_hash.read().clone(),
|
best_block_hash: self.last_hash.read().clone(),
|
||||||
best_block_number: self.blocks.read().len() as BlockNumber - 1,
|
best_block_number: number,
|
||||||
|
best_block_timestamp: number,
|
||||||
first_block_hash: self.first_block.read().as_ref().map(|x| x.0),
|
first_block_hash: self.first_block.read().as_ref().map(|x| x.0),
|
||||||
first_block_number: self.first_block.read().as_ref().map(|x| x.1),
|
first_block_number: self.first_block.read().as_ref().map(|x| x.1),
|
||||||
ancient_block_hash: self.ancient_block.read().as_ref().map(|x| x.0),
|
ancient_block_hash: self.ancient_block.read().as_ref().map(|x| x.0),
|
||||||
@ -690,7 +703,8 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn ready_transactions(&self) -> Vec<PendingTransaction> {
|
fn ready_transactions(&self) -> Vec<PendingTransaction> {
|
||||||
self.miner.ready_transactions(self.chain_info().best_block_number)
|
let info = self.chain_info();
|
||||||
|
self.miner.ready_transactions(info.best_block_number, info.best_block_timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signing_network_id(&self) -> Option<u64> { None }
|
fn signing_network_id(&self) -> Option<u64> { None }
|
||||||
|
@ -184,6 +184,9 @@ pub trait BlockChainClient : Sync + Send {
|
|||||||
/// Makes a non-persistent transaction call.
|
/// Makes a non-persistent transaction call.
|
||||||
fn call(&self, t: &SignedTransaction, block: BlockId, analytics: CallAnalytics) -> Result<Executed, CallError>;
|
fn call(&self, t: &SignedTransaction, block: BlockId, analytics: CallAnalytics) -> Result<Executed, CallError>;
|
||||||
|
|
||||||
|
/// Estimates how much gas will be necessary for a call.
|
||||||
|
fn estimate_gas(&self, t: &SignedTransaction, block: BlockId) -> Result<U256, CallError>;
|
||||||
|
|
||||||
/// Replays a given transaction for inspection.
|
/// Replays a given transaction for inspection.
|
||||||
fn replay(&self, t: TransactionId, analytics: CallAnalytics) -> Result<Executed, CallError>;
|
fn replay(&self, t: TransactionId, analytics: CallAnalytics) -> Result<Executed, CallError>;
|
||||||
|
|
||||||
@ -220,6 +223,7 @@ pub trait BlockChainClient : Sync + Send {
|
|||||||
let block = self.block(BlockId::Hash(h)).expect("h is either the best_block_hash or an ancestor; qed");
|
let block = self.block(BlockId::Hash(h)).expect("h is either the best_block_hash or an ancestor; qed");
|
||||||
let header = block.header_view();
|
let header = block.header_view();
|
||||||
if header.number() == 0 {
|
if header.number() == 0 {
|
||||||
|
corpus.sort();
|
||||||
return corpus;
|
return corpus;
|
||||||
}
|
}
|
||||||
block.transaction_views().iter().foreach(|t| corpus.push(t.gas_price()));
|
block.transaction_views().iter().foreach(|t| corpus.push(t.gas_price()));
|
||||||
|
@ -49,6 +49,8 @@ pub struct AuthorityRoundParams {
|
|||||||
pub step_duration: Duration,
|
pub step_duration: Duration,
|
||||||
/// Block reward.
|
/// Block reward.
|
||||||
pub block_reward: U256,
|
pub block_reward: U256,
|
||||||
|
/// Namereg contract address.
|
||||||
|
pub registrar: Address,
|
||||||
/// Starting step,
|
/// Starting step,
|
||||||
pub start_step: Option<u64>,
|
pub start_step: Option<u64>,
|
||||||
/// Valid validators.
|
/// Valid validators.
|
||||||
@ -62,6 +64,7 @@ impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
|
|||||||
step_duration: Duration::from_secs(p.step_duration.into()),
|
step_duration: Duration::from_secs(p.step_duration.into()),
|
||||||
validators: p.validators,
|
validators: p.validators,
|
||||||
block_reward: p.block_reward.map_or_else(U256::zero, Into::into),
|
block_reward: p.block_reward.map_or_else(U256::zero, Into::into),
|
||||||
|
registrar: p.registrar.map_or_else(Address::new, Into::into),
|
||||||
start_step: p.start_step.map(Into::into),
|
start_step: p.start_step.map(Into::into),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,6 +76,7 @@ pub struct AuthorityRound {
|
|||||||
params: CommonParams,
|
params: CommonParams,
|
||||||
gas_limit_bound_divisor: U256,
|
gas_limit_bound_divisor: U256,
|
||||||
block_reward: U256,
|
block_reward: U256,
|
||||||
|
registrar: Address,
|
||||||
step_duration: Duration,
|
step_duration: Duration,
|
||||||
builtins: BTreeMap<Address, Builtin>,
|
builtins: BTreeMap<Address, Builtin>,
|
||||||
transition_service: IoService<()>,
|
transition_service: IoService<()>,
|
||||||
@ -82,6 +86,8 @@ pub struct AuthorityRound {
|
|||||||
account_provider: Mutex<Arc<AccountProvider>>,
|
account_provider: Mutex<Arc<AccountProvider>>,
|
||||||
password: RwLock<Option<String>>,
|
password: RwLock<Option<String>>,
|
||||||
validators: Box<ValidatorSet + Send + Sync>,
|
validators: Box<ValidatorSet + Send + Sync>,
|
||||||
|
/// Is this Engine just for testing (prevents step calibration).
|
||||||
|
calibrate_step: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header_step(header: &Header) -> Result<usize, ::rlp::DecoderError> {
|
fn header_step(header: &Header) -> Result<usize, ::rlp::DecoderError> {
|
||||||
@ -112,6 +118,7 @@ impl AuthorityRound {
|
|||||||
params: params,
|
params: params,
|
||||||
gas_limit_bound_divisor: our_params.gas_limit_bound_divisor,
|
gas_limit_bound_divisor: our_params.gas_limit_bound_divisor,
|
||||||
block_reward: our_params.block_reward,
|
block_reward: our_params.block_reward,
|
||||||
|
registrar: our_params.registrar,
|
||||||
step_duration: our_params.step_duration,
|
step_duration: our_params.step_duration,
|
||||||
builtins: builtins,
|
builtins: builtins,
|
||||||
transition_service: IoService::<()>::start()?,
|
transition_service: IoService::<()>::start()?,
|
||||||
@ -121,6 +128,7 @@ impl AuthorityRound {
|
|||||||
account_provider: Mutex::new(Arc::new(AccountProvider::transient_provider())),
|
account_provider: Mutex::new(Arc::new(AccountProvider::transient_provider())),
|
||||||
password: RwLock::new(None),
|
password: RwLock::new(None),
|
||||||
validators: new_validator_set(our_params.validators),
|
validators: new_validator_set(our_params.validators),
|
||||||
|
calibrate_step: our_params.start_step.is_none(),
|
||||||
});
|
});
|
||||||
// Do not initialize timeouts for tests.
|
// Do not initialize timeouts for tests.
|
||||||
if should_timeout {
|
if should_timeout {
|
||||||
@ -130,6 +138,12 @@ impl AuthorityRound {
|
|||||||
Ok(engine)
|
Ok(engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn calibrate_step(&self) {
|
||||||
|
if self.calibrate_step {
|
||||||
|
self.step.store((unix_now().as_secs() / self.step_duration.as_secs()) as usize, AtomicOrdering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn remaining_step_duration(&self) -> Duration {
|
fn remaining_step_duration(&self) -> Duration {
|
||||||
let now = unix_now();
|
let now = unix_now();
|
||||||
let step_end = self.step_duration * (self.step.load(AtomicOrdering::SeqCst) as u32 + 1);
|
let step_end = self.step_duration * (self.step.load(AtomicOrdering::SeqCst) as u32 + 1);
|
||||||
@ -147,6 +161,16 @@ impl AuthorityRound {
|
|||||||
fn is_step_proposer(&self, step: usize, address: &Address) -> bool {
|
fn is_step_proposer(&self, step: usize, address: &Address) -> bool {
|
||||||
self.step_proposer(step) == *address
|
self.step_proposer(step) == *address
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_future_step(&self, step: usize) -> bool {
|
||||||
|
if step > self.step.load(AtomicOrdering::SeqCst) + 1 {
|
||||||
|
// Make absolutely sure that the step is correct.
|
||||||
|
self.calibrate_step();
|
||||||
|
step > self.step.load(AtomicOrdering::SeqCst) + 1
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unix_now() -> Duration {
|
fn unix_now() -> Duration {
|
||||||
@ -180,11 +204,16 @@ impl IoHandler<()> for TransitionHandler {
|
|||||||
|
|
||||||
impl Engine for AuthorityRound {
|
impl Engine for AuthorityRound {
|
||||||
fn name(&self) -> &str { "AuthorityRound" }
|
fn name(&self) -> &str { "AuthorityRound" }
|
||||||
|
|
||||||
fn version(&self) -> SemanticVersion { SemanticVersion::new(1, 0, 0) }
|
fn version(&self) -> SemanticVersion { SemanticVersion::new(1, 0, 0) }
|
||||||
|
|
||||||
/// Two fields - consensus step and the corresponding proposer signature.
|
/// Two fields - consensus step and the corresponding proposer signature.
|
||||||
fn seal_fields(&self) -> usize { 2 }
|
fn seal_fields(&self) -> usize { 2 }
|
||||||
|
|
||||||
fn params(&self) -> &CommonParams { &self.params }
|
fn params(&self) -> &CommonParams { &self.params }
|
||||||
|
|
||||||
|
fn additional_params(&self) -> HashMap<String, String> { hash_map!["registrar".to_owned() => self.registrar.hex()] }
|
||||||
|
|
||||||
fn builtins(&self) -> &BTreeMap<Address, Builtin> { &self.builtins }
|
fn builtins(&self) -> &BTreeMap<Address, Builtin> { &self.builtins }
|
||||||
|
|
||||||
fn step(&self) {
|
fn step(&self) {
|
||||||
@ -276,7 +305,10 @@ impl Engine for AuthorityRound {
|
|||||||
fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
|
fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
|
||||||
let header_step = header_step(header)?;
|
let header_step = header_step(header)?;
|
||||||
// Give one step slack if step is lagging, double vote is still not possible.
|
// Give one step slack if step is lagging, double vote is still not possible.
|
||||||
if header_step <= self.step.load(AtomicOrdering::SeqCst) + 1 {
|
if self.is_future_step(header_step) {
|
||||||
|
trace!(target: "engine", "verify_block_unordered: block from the future");
|
||||||
|
Err(BlockError::InvalidSeal)?
|
||||||
|
} else {
|
||||||
let proposer_signature = header_signature(header)?;
|
let proposer_signature = header_signature(header)?;
|
||||||
let ok_sig = verify_address(&self.step_proposer(header_step), &proposer_signature, &header.bare_hash())?;
|
let ok_sig = verify_address(&self.step_proposer(header_step), &proposer_signature, &header.bare_hash())?;
|
||||||
if ok_sig {
|
if ok_sig {
|
||||||
@ -285,9 +317,6 @@ impl Engine for AuthorityRound {
|
|||||||
trace!(target: "poa", "verify_block_unordered: invalid seal signature");
|
trace!(target: "poa", "verify_block_unordered: invalid seal signature");
|
||||||
Err(BlockError::InvalidSeal)?
|
Err(BlockError::InvalidSeal)?
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
trace!(target: "poa", "verify_block_unordered: block from the future");
|
|
||||||
Err(BlockError::InvalidSeal)?
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,6 +383,7 @@ mod tests {
|
|||||||
use env_info::EnvInfo;
|
use env_info::EnvInfo;
|
||||||
use header::Header;
|
use header::Header;
|
||||||
use error::{Error, BlockError};
|
use error::{Error, BlockError};
|
||||||
|
use ethkey::Secret;
|
||||||
use rlp::encode;
|
use rlp::encode;
|
||||||
use block::*;
|
use block::*;
|
||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
@ -411,8 +441,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn generates_seal_and_does_not_double_propose() {
|
fn generates_seal_and_does_not_double_propose() {
|
||||||
let tap = AccountProvider::transient_provider();
|
let tap = AccountProvider::transient_provider();
|
||||||
let addr1 = tap.insert_account("1".sha3(), "1").unwrap();
|
let addr1 = tap.insert_account(Secret::from_slice(&"1".sha3()).unwrap(), "1").unwrap();
|
||||||
let addr2 = tap.insert_account("2".sha3(), "2").unwrap();
|
let addr2 = tap.insert_account(Secret::from_slice(&"2".sha3()).unwrap(), "2").unwrap();
|
||||||
|
|
||||||
let spec = Spec::new_test_round();
|
let spec = Spec::new_test_round();
|
||||||
let engine = &*spec.engine;
|
let engine = &*spec.engine;
|
||||||
@ -445,7 +475,7 @@ mod tests {
|
|||||||
fn proposer_switching() {
|
fn proposer_switching() {
|
||||||
let mut header: Header = Header::default();
|
let mut header: Header = Header::default();
|
||||||
let tap = AccountProvider::transient_provider();
|
let tap = AccountProvider::transient_provider();
|
||||||
let addr = tap.insert_account("0".sha3(), "0").unwrap();
|
let addr = tap.insert_account(Secret::from_slice(&"0".sha3()).unwrap(), "0").unwrap();
|
||||||
|
|
||||||
header.set_author(addr);
|
header.set_author(addr);
|
||||||
|
|
||||||
@ -464,7 +494,7 @@ mod tests {
|
|||||||
fn rejects_future_block() {
|
fn rejects_future_block() {
|
||||||
let mut header: Header = Header::default();
|
let mut header: Header = Header::default();
|
||||||
let tap = AccountProvider::transient_provider();
|
let tap = AccountProvider::transient_provider();
|
||||||
let addr = tap.insert_account("0".sha3(), "0").unwrap();
|
let addr = tap.insert_account(Secret::from_slice(&"0".sha3()).unwrap(), "0").unwrap();
|
||||||
|
|
||||||
header.set_author(addr);
|
header.set_author(addr);
|
||||||
|
|
||||||
|
@ -201,6 +201,7 @@ mod tests {
|
|||||||
use error::{BlockError, Error};
|
use error::{BlockError, Error};
|
||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
use account_provider::AccountProvider;
|
use account_provider::AccountProvider;
|
||||||
|
use ethkey::Secret;
|
||||||
use header::Header;
|
use header::Header;
|
||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
use engines::Seal;
|
use engines::Seal;
|
||||||
@ -261,7 +262,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn can_generate_seal() {
|
fn can_generate_seal() {
|
||||||
let tap = AccountProvider::transient_provider();
|
let tap = AccountProvider::transient_provider();
|
||||||
let addr = tap.insert_account("".sha3(), "").unwrap();
|
let addr = tap.insert_account(Secret::from_slice(&"".sha3()).unwrap(), "").unwrap();
|
||||||
|
|
||||||
let spec = new_test_authority();
|
let spec = new_test_authority();
|
||||||
let engine = &*spec.engine;
|
let engine = &*spec.engine;
|
||||||
@ -281,7 +282,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn seals_internally() {
|
fn seals_internally() {
|
||||||
let tap = AccountProvider::transient_provider();
|
let tap = AccountProvider::transient_provider();
|
||||||
let authority = tap.insert_account("".sha3(), "").unwrap();
|
let authority = tap.insert_account(Secret::from_slice(&"".sha3()).unwrap(), "").unwrap();
|
||||||
|
|
||||||
let engine = new_test_authority().engine;
|
let engine = new_test_authority().engine;
|
||||||
assert!(!engine.is_sealer(&Address::default()).unwrap());
|
assert!(!engine.is_sealer(&Address::default()).unwrap());
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use util::Address;
|
use util::{Address, HashMap};
|
||||||
use builtin::Builtin;
|
use builtin::Builtin;
|
||||||
use engines::{Engine, Seal};
|
use engines::{Engine, Seal};
|
||||||
use env_info::EnvInfo;
|
use env_info::EnvInfo;
|
||||||
@ -26,14 +26,16 @@ use block::ExecutedBlock;
|
|||||||
/// An engine which does not provide any consensus mechanism, just seals blocks internally.
|
/// An engine which does not provide any consensus mechanism, just seals blocks internally.
|
||||||
pub struct InstantSeal {
|
pub struct InstantSeal {
|
||||||
params: CommonParams,
|
params: CommonParams,
|
||||||
|
registrar: Address,
|
||||||
builtins: BTreeMap<Address, Builtin>,
|
builtins: BTreeMap<Address, Builtin>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InstantSeal {
|
impl InstantSeal {
|
||||||
/// Returns new instance of InstantSeal with default VM Factory
|
/// Returns new instance of InstantSeal with default VM Factory
|
||||||
pub fn new(params: CommonParams, builtins: BTreeMap<Address, Builtin>) -> Self {
|
pub fn new(params: CommonParams, registrar: Address, builtins: BTreeMap<Address, Builtin>) -> Self {
|
||||||
InstantSeal {
|
InstantSeal {
|
||||||
params: params,
|
params: params,
|
||||||
|
registrar: registrar,
|
||||||
builtins: builtins,
|
builtins: builtins,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -48,6 +50,10 @@ impl Engine for InstantSeal {
|
|||||||
&self.params
|
&self.params
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn additional_params(&self) -> HashMap<String, String> {
|
||||||
|
hash_map!["registrar".to_owned() => self.registrar.hex()]
|
||||||
|
}
|
||||||
|
|
||||||
fn builtins(&self) -> &BTreeMap<Address, Builtin> {
|
fn builtins(&self) -> &BTreeMap<Address, Builtin> {
|
||||||
&self.builtins
|
&self.builtins
|
||||||
}
|
}
|
||||||
@ -76,9 +82,9 @@ mod tests {
|
|||||||
fn instant_can_seal() {
|
fn instant_can_seal() {
|
||||||
let spec = Spec::new_instant();
|
let spec = Spec::new_instant();
|
||||||
let engine = &*spec.engine;
|
let engine = &*spec.engine;
|
||||||
let genesis_header = spec.genesis_header();
|
|
||||||
let mut db_result = get_temp_state_db();
|
let mut db_result = get_temp_state_db();
|
||||||
let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap();
|
let db = spec.ensure_db_good(db_result.take(), &Default::default()).unwrap();
|
||||||
|
let genesis_header = spec.genesis_header();
|
||||||
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
||||||
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::default(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::default(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||||
let b = b.close_and_lock();
|
let b = b.close_and_lock();
|
||||||
|
@ -160,7 +160,9 @@ pub trait Engine : Sync + Send {
|
|||||||
fn verify_transaction(&self, _t: &SignedTransaction, _header: &Header) -> Result<(), Error> { Ok(()) }
|
fn verify_transaction(&self, _t: &SignedTransaction, _header: &Header) -> Result<(), Error> { Ok(()) }
|
||||||
|
|
||||||
/// The network ID that transactions should be signed with.
|
/// The network ID that transactions should be signed with.
|
||||||
fn signing_network_id(&self, _env_info: &EnvInfo) -> Option<u64> { None }
|
fn signing_network_id(&self, _env_info: &EnvInfo) -> Option<u64> {
|
||||||
|
Some(self.params().chain_id)
|
||||||
|
}
|
||||||
|
|
||||||
/// Verify the seal of a block. This is an auxilliary method that actually just calls other `verify_` methods
|
/// Verify the seal of a block. This is an auxilliary method that actually just calls other `verify_` methods
|
||||||
/// to get the job done. By default it must pass `verify_basic` and `verify_block_unordered`. If more or fewer
|
/// to get the job done. By default it must pass `verify_basic` and `verify_block_unordered`. If more or fewer
|
||||||
|
@ -23,15 +23,35 @@ use header::Header;
|
|||||||
use rlp::*;
|
use rlp::*;
|
||||||
use ethkey::{recover, public_to_address};
|
use ethkey::{recover, public_to_address};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
/// Message transmitted between consensus participants.
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
||||||
pub struct ConsensusMessage {
|
pub struct ConsensusMessage {
|
||||||
|
pub vote_step: VoteStep,
|
||||||
|
pub block_hash: Option<BlockHash>,
|
||||||
pub signature: H520,
|
pub signature: H520,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Complete step of the consensus process.
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
||||||
|
pub struct VoteStep {
|
||||||
pub height: Height,
|
pub height: Height,
|
||||||
pub round: Round,
|
pub round: Round,
|
||||||
pub step: Step,
|
pub step: Step,
|
||||||
pub block_hash: Option<BlockHash>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl VoteStep {
|
||||||
|
pub fn new(height: Height, round: Round, step: Step) -> Self {
|
||||||
|
VoteStep { height: height, round: round, step: step }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_height(&self, height: Height) -> bool {
|
||||||
|
self.height == height
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_round(&self, height: Height, round: Round) -> bool {
|
||||||
|
self.height == height && self.round == round
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn consensus_round(header: &Header) -> Result<Round, ::rlp::DecoderError> {
|
fn consensus_round(header: &Header) -> Result<Round, ::rlp::DecoderError> {
|
||||||
let round_rlp = header.seal().get(0).expect("seal passed basic verification; seal has 3 fields; qed");
|
let round_rlp = header.seal().get(0).expect("seal passed basic verification; seal has 3 fields; qed");
|
||||||
@ -42,53 +62,29 @@ impl ConsensusMessage {
|
|||||||
pub fn new(signature: H520, height: Height, round: Round, step: Step, block_hash: Option<BlockHash>) -> Self {
|
pub fn new(signature: H520, height: Height, round: Round, step: Step, block_hash: Option<BlockHash>) -> Self {
|
||||||
ConsensusMessage {
|
ConsensusMessage {
|
||||||
signature: signature,
|
signature: signature,
|
||||||
height: height,
|
|
||||||
round: round,
|
|
||||||
step: step,
|
|
||||||
block_hash: block_hash,
|
block_hash: block_hash,
|
||||||
|
vote_step: VoteStep::new(height, round, step),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_proposal(header: &Header) -> Result<Self, ::rlp::DecoderError> {
|
pub fn new_proposal(header: &Header) -> Result<Self, ::rlp::DecoderError> {
|
||||||
Ok(ConsensusMessage {
|
Ok(ConsensusMessage {
|
||||||
|
vote_step: VoteStep::new(header.number() as Height, consensus_round(header)?, Step::Propose),
|
||||||
signature: UntrustedRlp::new(header.seal().get(1).expect("seal passed basic verification; seal has 3 fields; qed").as_slice()).as_val()?,
|
signature: UntrustedRlp::new(header.seal().get(1).expect("seal passed basic verification; seal has 3 fields; qed").as_slice()).as_val()?,
|
||||||
height: header.number() as Height,
|
|
||||||
round: consensus_round(header)?,
|
|
||||||
step: Step::Propose,
|
|
||||||
block_hash: Some(header.bare_hash()),
|
block_hash: Some(header.bare_hash()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_commit(proposal: &ConsensusMessage, signature: H520) -> Self {
|
pub fn new_commit(proposal: &ConsensusMessage, signature: H520) -> Self {
|
||||||
|
let mut vote_step = proposal.vote_step.clone();
|
||||||
|
vote_step.step = Step::Precommit;
|
||||||
ConsensusMessage {
|
ConsensusMessage {
|
||||||
signature: signature,
|
vote_step: vote_step,
|
||||||
height: proposal.height,
|
|
||||||
round: proposal.round,
|
|
||||||
step: Step::Precommit,
|
|
||||||
block_hash: proposal.block_hash,
|
block_hash: proposal.block_hash,
|
||||||
|
signature: signature,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_height(&self, height: Height) -> bool {
|
|
||||||
self.height == height
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_round(&self, height: Height, round: Round) -> bool {
|
|
||||||
self.height == height && self.round == round
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_step(&self, height: Height, round: Round, step: Step) -> bool {
|
|
||||||
self.height == height && self.round == round && self.step == step
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_block_hash(&self, h: Height, r: Round, s: Step, block_hash: Option<BlockHash>) -> bool {
|
|
||||||
self.height == h && self.round == r && self.step == s && self.block_hash == block_hash
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_aligned(&self, m: &ConsensusMessage) -> bool {
|
|
||||||
self.is_block_hash(m.height, m.round, m.step, m.block_hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn verify(&self) -> Result<Address, Error> {
|
pub fn verify(&self) -> Result<Address, Error> {
|
||||||
let full_rlp = ::rlp::encode(self);
|
let full_rlp = ::rlp::encode(self);
|
||||||
let block_info = Rlp::new(&full_rlp).at(1);
|
let block_info = Rlp::new(&full_rlp).at(1);
|
||||||
@ -97,16 +93,30 @@ impl ConsensusMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn precommit_hash(&self) -> H256 {
|
pub fn precommit_hash(&self) -> H256 {
|
||||||
message_info_rlp(self.height, self.round, Step::Precommit, self.block_hash).sha3()
|
let mut vote_step = self.vote_step.clone();
|
||||||
|
vote_step.step = Step::Precommit;
|
||||||
|
message_info_rlp(&vote_step, self.block_hash).sha3()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for ConsensusMessage {
|
impl PartialOrd for VoteStep {
|
||||||
fn partial_cmp(&self, m: &ConsensusMessage) -> Option<Ordering> {
|
fn partial_cmp(&self, m: &VoteStep) -> Option<Ordering> {
|
||||||
Some(self.cmp(m))
|
Some(self.cmp(m))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Ord for VoteStep {
|
||||||
|
fn cmp(&self, m: &VoteStep) -> Ordering {
|
||||||
|
if self.height != m.height {
|
||||||
|
self.height.cmp(&m.height)
|
||||||
|
} else if self.round != m.round {
|
||||||
|
self.round.cmp(&m.round)
|
||||||
|
} else {
|
||||||
|
self.step.number().cmp(&m.step.number())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Step {
|
impl Step {
|
||||||
fn number(&self) -> u8 {
|
fn number(&self) -> u8 {
|
||||||
match *self {
|
match *self {
|
||||||
@ -118,20 +128,6 @@ impl Step {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for ConsensusMessage {
|
|
||||||
fn cmp(&self, m: &ConsensusMessage) -> Ordering {
|
|
||||||
if self.height != m.height {
|
|
||||||
self.height.cmp(&m.height)
|
|
||||||
} else if self.round != m.round {
|
|
||||||
self.round.cmp(&m.round)
|
|
||||||
} else if self.step != m.step {
|
|
||||||
self.step.number().cmp(&m.step.number())
|
|
||||||
} else {
|
|
||||||
self.signature.cmp(&m.signature)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Decodable for Step {
|
impl Decodable for Step {
|
||||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||||
match decoder.as_rlp().as_val()? {
|
match decoder.as_rlp().as_val()? {
|
||||||
@ -149,42 +145,39 @@ impl Encodable for Step {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// (signature, height, round, step, block_hash)
|
/// (signature, (height, round, step, block_hash))
|
||||||
impl Decodable for ConsensusMessage {
|
impl Decodable for ConsensusMessage {
|
||||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||||
let rlp = decoder.as_rlp();
|
let rlp = decoder.as_rlp();
|
||||||
let m = rlp.at(1)?;
|
let m = rlp.at(1)?;
|
||||||
let block_message: H256 = m.val_at(3)?;
|
let block_message: H256 = m.val_at(3)?;
|
||||||
Ok(ConsensusMessage {
|
Ok(ConsensusMessage {
|
||||||
signature: rlp.val_at(0)?,
|
vote_step: VoteStep::new(m.val_at(0)?, m.val_at(1)?, m.val_at(2)?),
|
||||||
height: m.val_at(0)?,
|
|
||||||
round: m.val_at(1)?,
|
|
||||||
step: m.val_at(2)?,
|
|
||||||
block_hash: match block_message.is_zero() {
|
block_hash: match block_message.is_zero() {
|
||||||
true => None,
|
true => None,
|
||||||
false => Some(block_message),
|
false => Some(block_message),
|
||||||
}
|
},
|
||||||
|
signature: rlp.val_at(0)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encodable for ConsensusMessage {
|
impl Encodable for ConsensusMessage {
|
||||||
fn rlp_append(&self, s: &mut RlpStream) {
|
fn rlp_append(&self, s: &mut RlpStream) {
|
||||||
let info = message_info_rlp(self.height, self.round, self.step, self.block_hash);
|
let info = message_info_rlp(&self.vote_step, self.block_hash);
|
||||||
s.begin_list(2)
|
s.begin_list(2)
|
||||||
.append(&self.signature)
|
.append(&self.signature)
|
||||||
.append_raw(&info, 1);
|
.append_raw(&info, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn message_info_rlp(height: Height, round: Round, step: Step, block_hash: Option<BlockHash>) -> Bytes {
|
pub fn message_info_rlp(vote_step: &VoteStep, block_hash: Option<BlockHash>) -> Bytes {
|
||||||
// TODO: figure out whats wrong with nested list encoding
|
// TODO: figure out whats wrong with nested list encoding
|
||||||
let mut s = RlpStream::new_list(5);
|
let mut s = RlpStream::new_list(5);
|
||||||
s.append(&height).append(&round).append(&step).append(&block_hash.unwrap_or_else(H256::zero));
|
s.append(&vote_step.height).append(&vote_step.round).append(&vote_step.step).append(&block_hash.unwrap_or_else(H256::zero));
|
||||||
s.out()
|
s.out()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn message_full_rlp(signature: &H520, vote_info: &Bytes) -> Bytes {
|
pub fn message_full_rlp(signature: &H520, vote_info: &Bytes) -> Bytes {
|
||||||
let mut s = RlpStream::new_list(2);
|
let mut s = RlpStream::new_list(2);
|
||||||
s.append(signature).append_raw(vote_info, 1);
|
s.append(signature).append_raw(vote_info, 1);
|
||||||
@ -199,14 +192,17 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use account_provider::AccountProvider;
|
use account_provider::AccountProvider;
|
||||||
use header::Header;
|
use header::Header;
|
||||||
|
use ethkey::Secret;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn encode_decode() {
|
fn encode_decode() {
|
||||||
let message = ConsensusMessage {
|
let message = ConsensusMessage {
|
||||||
signature: H520::default(),
|
signature: H520::default(),
|
||||||
|
vote_step: VoteStep {
|
||||||
height: 10,
|
height: 10,
|
||||||
round: 123,
|
round: 123,
|
||||||
step: Step::Precommit,
|
step: Step::Precommit,
|
||||||
|
},
|
||||||
block_hash: Some("1".sha3())
|
block_hash: Some("1".sha3())
|
||||||
};
|
};
|
||||||
let raw_rlp = ::rlp::encode(&message).to_vec();
|
let raw_rlp = ::rlp::encode(&message).to_vec();
|
||||||
@ -215,9 +211,11 @@ mod tests {
|
|||||||
|
|
||||||
let message = ConsensusMessage {
|
let message = ConsensusMessage {
|
||||||
signature: H520::default(),
|
signature: H520::default(),
|
||||||
|
vote_step: VoteStep {
|
||||||
height: 1314,
|
height: 1314,
|
||||||
round: 0,
|
round: 0,
|
||||||
step: Step::Prevote,
|
step: Step::Prevote,
|
||||||
|
},
|
||||||
block_hash: None
|
block_hash: None
|
||||||
};
|
};
|
||||||
let raw_rlp = ::rlp::encode(&message);
|
let raw_rlp = ::rlp::encode(&message);
|
||||||
@ -228,10 +226,10 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn generate_and_verify() {
|
fn generate_and_verify() {
|
||||||
let tap = Arc::new(AccountProvider::transient_provider());
|
let tap = Arc::new(AccountProvider::transient_provider());
|
||||||
let addr = tap.insert_account("0".sha3(), "0").unwrap();
|
let addr = tap.insert_account(Secret::from_slice(&"0".sha3()).unwrap(), "0").unwrap();
|
||||||
tap.unlock_account_permanently(addr, "0".into()).unwrap();
|
tap.unlock_account_permanently(addr, "0".into()).unwrap();
|
||||||
|
|
||||||
let mi = message_info_rlp(123, 2, Step::Precommit, Some(H256::default()));
|
let mi = message_info_rlp(&VoteStep::new(123, 2, Step::Precommit), Some(H256::default()));
|
||||||
|
|
||||||
let raw_rlp = message_full_rlp(&tap.sign(addr, None, mi.sha3()).unwrap().into(), &mi);
|
let raw_rlp = message_full_rlp(&tap.sign(addr, None, mi.sha3()).unwrap().into(), &mi);
|
||||||
|
|
||||||
@ -254,9 +252,11 @@ mod tests {
|
|||||||
message,
|
message,
|
||||||
ConsensusMessage {
|
ConsensusMessage {
|
||||||
signature: Default::default(),
|
signature: Default::default(),
|
||||||
|
vote_step: VoteStep {
|
||||||
height: 0,
|
height: 0,
|
||||||
round: 0,
|
round: 0,
|
||||||
step: Step::Propose,
|
step: Step::Propose,
|
||||||
|
},
|
||||||
block_hash: Some(header.bare_hash())
|
block_hash: Some(header.bare_hash())
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -267,12 +267,10 @@ mod tests {
|
|||||||
let header = Header::default();
|
let header = Header::default();
|
||||||
let pro = ConsensusMessage {
|
let pro = ConsensusMessage {
|
||||||
signature: Default::default(),
|
signature: Default::default(),
|
||||||
height: 0,
|
vote_step: VoteStep::new(0, 0, Step::Propose),
|
||||||
round: 0,
|
|
||||||
step: Step::Propose,
|
|
||||||
block_hash: Some(header.bare_hash())
|
block_hash: Some(header.bare_hash())
|
||||||
};
|
};
|
||||||
let pre = message_info_rlp(0, 0, Step::Precommit, Some(header.bare_hash()));
|
let pre = message_info_rlp(&VoteStep::new(0, 0, Step::Precommit), Some(header.bare_hash()));
|
||||||
|
|
||||||
assert_eq!(pro.precommit_hash(), pre.sha3());
|
assert_eq!(pro.precommit_hash(), pre.sha3());
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ use self::transition::TransitionHandler;
|
|||||||
use self::params::TendermintParams;
|
use self::params::TendermintParams;
|
||||||
use self::vote_collector::VoteCollector;
|
use self::vote_collector::VoteCollector;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
|
||||||
pub enum Step {
|
pub enum Step {
|
||||||
Propose,
|
Propose,
|
||||||
Prevote,
|
Prevote,
|
||||||
@ -86,6 +86,7 @@ pub struct Tendermint {
|
|||||||
authority: RwLock<Address>,
|
authority: RwLock<Address>,
|
||||||
/// Password used for signing messages.
|
/// Password used for signing messages.
|
||||||
password: RwLock<Option<String>>,
|
password: RwLock<Option<String>>,
|
||||||
|
registrar: Address,
|
||||||
/// Blockchain height.
|
/// Blockchain height.
|
||||||
height: AtomicUsize,
|
height: AtomicUsize,
|
||||||
/// Consensus round.
|
/// Consensus round.
|
||||||
@ -119,6 +120,7 @@ impl Tendermint {
|
|||||||
block_reward: our_params.block_reward,
|
block_reward: our_params.block_reward,
|
||||||
authority: RwLock::new(Address::default()),
|
authority: RwLock::new(Address::default()),
|
||||||
password: RwLock::new(None),
|
password: RwLock::new(None),
|
||||||
|
registrar: our_params.registrar,
|
||||||
height: AtomicUsize::new(1),
|
height: AtomicUsize::new(1),
|
||||||
round: AtomicUsize::new(0),
|
round: AtomicUsize::new(0),
|
||||||
step: RwLock::new(Step::Propose),
|
step: RwLock::new(Step::Propose),
|
||||||
@ -163,13 +165,13 @@ impl Tendermint {
|
|||||||
let h = self.height.load(AtomicOrdering::SeqCst);
|
let h = self.height.load(AtomicOrdering::SeqCst);
|
||||||
let r = self.round.load(AtomicOrdering::SeqCst);
|
let r = self.round.load(AtomicOrdering::SeqCst);
|
||||||
let s = self.step.read();
|
let s = self.step.read();
|
||||||
let vote_info = message_info_rlp(h, r, *s, block_hash);
|
let vote_info = message_info_rlp(&VoteStep::new(h, r, *s), block_hash);
|
||||||
let authority = self.authority.read();
|
let authority = self.authority.read();
|
||||||
match ap.sign(*authority, self.password.read().clone(), vote_info.sha3()).map(Into::into) {
|
match ap.sign(*authority, self.password.read().clone(), vote_info.sha3()).map(Into::into) {
|
||||||
Ok(signature) => {
|
Ok(signature) => {
|
||||||
let message_rlp = message_full_rlp(&signature, &vote_info);
|
let message_rlp = message_full_rlp(&signature, &vote_info);
|
||||||
let message = ConsensusMessage::new(signature, h, r, *s, block_hash);
|
let message = ConsensusMessage::new(signature, h, r, *s, block_hash);
|
||||||
self.votes.vote(message.clone(), *authority);
|
self.votes.vote(message.clone(), &*authority);
|
||||||
debug!(target: "poa", "Generated {:?} as {}.", message, *authority);
|
debug!(target: "poa", "Generated {:?} as {}.", message, *authority);
|
||||||
self.handle_valid_message(&message);
|
self.handle_valid_message(&message);
|
||||||
|
|
||||||
@ -221,7 +223,7 @@ impl Tendermint {
|
|||||||
},
|
},
|
||||||
Step::Prevote => {
|
Step::Prevote => {
|
||||||
let block_hash = match *self.lock_change.read() {
|
let block_hash = match *self.lock_change.read() {
|
||||||
Some(ref m) if !self.should_unlock(m.round) => m.block_hash,
|
Some(ref m) if !self.should_unlock(m.vote_step.round) => m.block_hash,
|
||||||
_ => self.proposal.read().clone(),
|
_ => self.proposal.read().clone(),
|
||||||
};
|
};
|
||||||
self.generate_and_broadcast_message(block_hash);
|
self.generate_and_broadcast_message(block_hash);
|
||||||
@ -230,8 +232,8 @@ impl Tendermint {
|
|||||||
trace!(target: "poa", "to_step: Precommit.");
|
trace!(target: "poa", "to_step: Precommit.");
|
||||||
let block_hash = match *self.lock_change.read() {
|
let block_hash = match *self.lock_change.read() {
|
||||||
Some(ref m) if self.is_round(m) && m.block_hash.is_some() => {
|
Some(ref m) if self.is_round(m) && m.block_hash.is_some() => {
|
||||||
trace!(target: "poa", "Setting last lock: {}", m.round);
|
trace!(target: "poa", "Setting last lock: {}", m.vote_step.round);
|
||||||
self.last_lock.store(m.round, AtomicOrdering::SeqCst);
|
self.last_lock.store(m.vote_step.round, AtomicOrdering::SeqCst);
|
||||||
m.block_hash
|
m.block_hash
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -246,7 +248,7 @@ impl Tendermint {
|
|||||||
if let Some(block_hash) = *self.proposal.read() {
|
if let Some(block_hash) = *self.proposal.read() {
|
||||||
// Generate seal and remove old votes.
|
// Generate seal and remove old votes.
|
||||||
if self.is_proposer(&*self.authority.read()).is_ok() {
|
if self.is_proposer(&*self.authority.read()).is_ok() {
|
||||||
if let Some(seal) = self.votes.seal_signatures(height, round, block_hash) {
|
if let Some(seal) = self.votes.seal_signatures(height, round, &block_hash) {
|
||||||
trace!(target: "poa", "Collected seal: {:?}", seal);
|
trace!(target: "poa", "Collected seal: {:?}", seal);
|
||||||
let seal = vec![
|
let seal = vec![
|
||||||
::rlp::encode(&round).to_vec(),
|
::rlp::encode(&round).to_vec(),
|
||||||
@ -290,11 +292,11 @@ impl Tendermint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_height(&self, message: &ConsensusMessage) -> bool {
|
fn is_height(&self, message: &ConsensusMessage) -> bool {
|
||||||
message.is_height(self.height.load(AtomicOrdering::SeqCst))
|
message.vote_step.is_height(self.height.load(AtomicOrdering::SeqCst))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_round(&self, message: &ConsensusMessage) -> bool {
|
fn is_round(&self, message: &ConsensusMessage) -> bool {
|
||||||
message.is_round(self.height.load(AtomicOrdering::SeqCst), self.round.load(AtomicOrdering::SeqCst))
|
message.vote_step.is_round(self.height.load(AtomicOrdering::SeqCst), self.round.load(AtomicOrdering::SeqCst))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn increment_round(&self, n: Round) {
|
fn increment_round(&self, n: Round) {
|
||||||
@ -309,13 +311,13 @@ impl Tendermint {
|
|||||||
|
|
||||||
|
|
||||||
fn has_enough_any_votes(&self) -> bool {
|
fn has_enough_any_votes(&self) -> bool {
|
||||||
let step_votes = self.votes.count_step_votes(self.height.load(AtomicOrdering::SeqCst), self.round.load(AtomicOrdering::SeqCst), *self.step.read());
|
let step_votes = self.votes.count_step_votes(&VoteStep::new(self.height.load(AtomicOrdering::SeqCst), self.round.load(AtomicOrdering::SeqCst), *self.step.read()));
|
||||||
self.is_above_threshold(step_votes)
|
self.is_above_threshold(step_votes)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_enough_future_step_votes(&self, message: &ConsensusMessage) -> bool {
|
fn has_enough_future_step_votes(&self, vote_step: &VoteStep) -> bool {
|
||||||
if message.round > self.round.load(AtomicOrdering::SeqCst) {
|
if vote_step.round > self.round.load(AtomicOrdering::SeqCst) {
|
||||||
let step_votes = self.votes.count_step_votes(message.height, message.round, message.step);
|
let step_votes = self.votes.count_step_votes(vote_step);
|
||||||
self.is_above_threshold(step_votes)
|
self.is_above_threshold(step_votes)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@ -328,12 +330,13 @@ impl Tendermint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_valid_message(&self, message: &ConsensusMessage) {
|
fn handle_valid_message(&self, message: &ConsensusMessage) {
|
||||||
|
let ref vote_step = message.vote_step;
|
||||||
let is_newer_than_lock = match *self.lock_change.read() {
|
let is_newer_than_lock = match *self.lock_change.read() {
|
||||||
Some(ref lock) => message > lock,
|
Some(ref lock) => vote_step > &lock.vote_step,
|
||||||
None => true,
|
None => true,
|
||||||
};
|
};
|
||||||
let lock_change = is_newer_than_lock
|
let lock_change = is_newer_than_lock
|
||||||
&& message.step == Step::Prevote
|
&& vote_step.step == Step::Prevote
|
||||||
&& message.block_hash.is_some()
|
&& message.block_hash.is_some()
|
||||||
&& self.has_enough_aligned_votes(message);
|
&& self.has_enough_aligned_votes(message);
|
||||||
if lock_change {
|
if lock_change {
|
||||||
@ -351,15 +354,15 @@ impl Tendermint {
|
|||||||
Some(Step::Commit)
|
Some(Step::Commit)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Step::Precommit if self.has_enough_future_step_votes(message) => {
|
Step::Precommit if self.has_enough_future_step_votes(&vote_step) => {
|
||||||
self.increment_round(message.round - self.round.load(AtomicOrdering::SeqCst));
|
self.increment_round(vote_step.round - self.round.load(AtomicOrdering::SeqCst));
|
||||||
Some(Step::Precommit)
|
Some(Step::Precommit)
|
||||||
},
|
},
|
||||||
// Avoid counting twice.
|
// Avoid counting twice.
|
||||||
Step::Prevote if lock_change => Some(Step::Precommit),
|
Step::Prevote if lock_change => Some(Step::Precommit),
|
||||||
Step::Prevote if self.has_enough_aligned_votes(message) => Some(Step::Precommit),
|
Step::Prevote if self.has_enough_aligned_votes(message) => Some(Step::Precommit),
|
||||||
Step::Prevote if self.has_enough_future_step_votes(message) => {
|
Step::Prevote if self.has_enough_future_step_votes(&vote_step) => {
|
||||||
self.increment_round(message.round - self.round.load(AtomicOrdering::SeqCst));
|
self.increment_round(vote_step.round - self.round.load(AtomicOrdering::SeqCst));
|
||||||
Some(Step::Prevote)
|
Some(Step::Prevote)
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -375,14 +378,20 @@ impl Tendermint {
|
|||||||
|
|
||||||
impl Engine for Tendermint {
|
impl Engine for Tendermint {
|
||||||
fn name(&self) -> &str { "Tendermint" }
|
fn name(&self) -> &str { "Tendermint" }
|
||||||
|
|
||||||
fn version(&self) -> SemanticVersion { SemanticVersion::new(1, 0, 0) }
|
fn version(&self) -> SemanticVersion { SemanticVersion::new(1, 0, 0) }
|
||||||
|
|
||||||
/// (consensus round, proposal signature, authority signatures)
|
/// (consensus round, proposal signature, authority signatures)
|
||||||
fn seal_fields(&self) -> usize { 3 }
|
fn seal_fields(&self) -> usize { 3 }
|
||||||
|
|
||||||
fn params(&self) -> &CommonParams { &self.params }
|
fn params(&self) -> &CommonParams { &self.params }
|
||||||
|
|
||||||
|
fn additional_params(&self) -> HashMap<String, String> { hash_map!["registrar".to_owned() => self.registrar.hex()] }
|
||||||
|
|
||||||
fn builtins(&self) -> &BTreeMap<Address, Builtin> { &self.builtins }
|
fn builtins(&self) -> &BTreeMap<Address, Builtin> { &self.builtins }
|
||||||
|
|
||||||
fn maximum_uncle_count(&self) -> usize { 0 }
|
fn maximum_uncle_count(&self) -> usize { 0 }
|
||||||
|
|
||||||
fn maximum_uncle_age(&self) -> usize { 0 }
|
fn maximum_uncle_age(&self) -> usize { 0 }
|
||||||
|
|
||||||
/// Additional engine-specific information for the user/developer concerning `header`.
|
/// Additional engine-specific information for the user/developer concerning `header`.
|
||||||
@ -390,8 +399,8 @@ impl Engine for Tendermint {
|
|||||||
let message = ConsensusMessage::new_proposal(header).expect("Invalid header.");
|
let message = ConsensusMessage::new_proposal(header).expect("Invalid header.");
|
||||||
map![
|
map![
|
||||||
"signature".into() => message.signature.to_string(),
|
"signature".into() => message.signature.to_string(),
|
||||||
"height".into() => message.height.to_string(),
|
"height".into() => message.vote_step.height.to_string(),
|
||||||
"round".into() => message.round.to_string(),
|
"round".into() => message.vote_step.round.to_string(),
|
||||||
"block_hash".into() => message.block_hash.as_ref().map(ToString::to_string).unwrap_or("".into())
|
"block_hash".into() => message.block_hash.as_ref().map(ToString::to_string).unwrap_or("".into())
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -431,11 +440,11 @@ impl Engine for Tendermint {
|
|||||||
let height = header.number() as Height;
|
let height = header.number() as Height;
|
||||||
let round = self.round.load(AtomicOrdering::SeqCst);
|
let round = self.round.load(AtomicOrdering::SeqCst);
|
||||||
let bh = Some(header.bare_hash());
|
let bh = Some(header.bare_hash());
|
||||||
let vote_info = message_info_rlp(height, round, Step::Propose, bh.clone());
|
let vote_info = message_info_rlp(&VoteStep::new(height, round, Step::Propose), bh.clone());
|
||||||
if let Ok(signature) = ap.sign(*author, self.password.read().clone(), vote_info.sha3()).map(H520::from) {
|
if let Ok(signature) = ap.sign(*author, self.password.read().clone(), vote_info.sha3()).map(H520::from) {
|
||||||
// Insert Propose vote.
|
// Insert Propose vote.
|
||||||
debug!(target: "poa", "Submitting proposal {} at height {} round {}.", header.bare_hash(), height, round);
|
debug!(target: "poa", "Submitting proposal {} at height {} round {}.", header.bare_hash(), height, round);
|
||||||
self.votes.vote(ConsensusMessage::new(signature, height, round, Step::Propose, bh), *author);
|
self.votes.vote(ConsensusMessage::new(signature, height, round, Step::Propose, bh), author);
|
||||||
// Remember proposal for later seal submission.
|
// Remember proposal for later seal submission.
|
||||||
*self.proposal.write() = bh;
|
*self.proposal.write() = bh;
|
||||||
Seal::Proposal(vec![
|
Seal::Proposal(vec![
|
||||||
@ -461,9 +470,11 @@ impl Engine for Tendermint {
|
|||||||
if !self.is_authority(&sender) {
|
if !self.is_authority(&sender) {
|
||||||
Err(EngineError::NotAuthorized(sender))?;
|
Err(EngineError::NotAuthorized(sender))?;
|
||||||
}
|
}
|
||||||
self.broadcast_message(rlp.as_raw().to_vec());
|
if self.votes.vote(message.clone(), &sender).is_some() {
|
||||||
|
Err(EngineError::DoubleVote(sender))?
|
||||||
|
}
|
||||||
trace!(target: "poa", "Handling a valid {:?} from {}.", message, sender);
|
trace!(target: "poa", "Handling a valid {:?} from {}.", message, sender);
|
||||||
self.votes.vote(message.clone(), sender);
|
self.broadcast_message(rlp.as_raw().to_vec());
|
||||||
self.handle_valid_message(&message);
|
self.handle_valid_message(&message);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -541,7 +552,7 @@ impl Engine for Tendermint {
|
|||||||
found: signatures_len
|
found: signatures_len
|
||||||
}))?;
|
}))?;
|
||||||
}
|
}
|
||||||
self.is_round_proposer(proposal.height, proposal.round, &proposer)?;
|
self.is_round_proposer(proposal.vote_step.height, proposal.vote_step.round, &proposer)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -607,16 +618,16 @@ impl Engine for Tendermint {
|
|||||||
let proposal = ConsensusMessage::new_proposal(header).expect("block went through full verification; this Engine verifies new_proposal creation; qed");
|
let proposal = ConsensusMessage::new_proposal(header).expect("block went through full verification; this Engine verifies new_proposal creation; qed");
|
||||||
if signatures_len != 1 {
|
if signatures_len != 1 {
|
||||||
// New Commit received, skip to next height.
|
// New Commit received, skip to next height.
|
||||||
trace!(target: "poa", "Received a commit for height {}, round {}.", proposal.height, proposal.round);
|
trace!(target: "poa", "Received a commit: {:?}.", proposal.vote_step);
|
||||||
self.to_next_height(proposal.height);
|
self.to_next_height(proposal.vote_step.height);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let proposer = proposal.verify().expect("block went through full verification; this Engine tries verify; qed");
|
let proposer = proposal.verify().expect("block went through full verification; this Engine tries verify; qed");
|
||||||
debug!(target: "poa", "Received a new proposal for height {}, round {} from {}.", proposal.height, proposal.round, proposer);
|
debug!(target: "poa", "Received a new proposal {:?} from {}.", proposal.vote_step, proposer);
|
||||||
if self.is_round(&proposal) {
|
if self.is_round(&proposal) {
|
||||||
*self.proposal.write() = proposal.block_hash.clone();
|
*self.proposal.write() = proposal.block_hash.clone();
|
||||||
}
|
}
|
||||||
self.votes.vote(proposal, proposer);
|
self.votes.vote(proposal, &proposer);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -671,6 +682,7 @@ mod tests {
|
|||||||
use error::{Error, BlockError};
|
use error::{Error, BlockError};
|
||||||
use header::Header;
|
use header::Header;
|
||||||
use env_info::EnvInfo;
|
use env_info::EnvInfo;
|
||||||
|
use ethkey::Secret;
|
||||||
use client::chain_notify::ChainNotify;
|
use client::chain_notify::ChainNotify;
|
||||||
use miner::MinerService;
|
use miner::MinerService;
|
||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
@ -703,7 +715,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn vote<F>(engine: &Engine, signer: F, height: usize, round: usize, step: Step, block_hash: Option<H256>) -> Bytes where F: FnOnce(H256) -> Result<H520, ::account_provider::Error> {
|
fn vote<F>(engine: &Engine, signer: F, height: usize, round: usize, step: Step, block_hash: Option<H256>) -> Bytes where F: FnOnce(H256) -> Result<H520, ::account_provider::Error> {
|
||||||
let mi = message_info_rlp(height, round, step, block_hash);
|
let mi = message_info_rlp(&VoteStep::new(height, round, step), block_hash);
|
||||||
let m = message_full_rlp(&signer(mi.sha3()).unwrap().into(), &mi);
|
let m = message_full_rlp(&signer(mi.sha3()).unwrap().into(), &mi);
|
||||||
engine.handle_message(&m).unwrap();
|
engine.handle_message(&m).unwrap();
|
||||||
m
|
m
|
||||||
@ -711,7 +723,7 @@ mod tests {
|
|||||||
|
|
||||||
fn proposal_seal(tap: &Arc<AccountProvider>, header: &Header, round: Round) -> Vec<Bytes> {
|
fn proposal_seal(tap: &Arc<AccountProvider>, header: &Header, round: Round) -> Vec<Bytes> {
|
||||||
let author = header.author();
|
let author = header.author();
|
||||||
let vote_info = message_info_rlp(header.number() as Height, round, Step::Propose, Some(header.bare_hash()));
|
let vote_info = message_info_rlp(&VoteStep::new(header.number() as Height, round, Step::Propose), Some(header.bare_hash()));
|
||||||
let signature = tap.sign(*author, None, vote_info.sha3()).unwrap();
|
let signature = tap.sign(*author, None, vote_info.sha3()).unwrap();
|
||||||
vec![
|
vec![
|
||||||
::rlp::encode(&round).to_vec(),
|
::rlp::encode(&round).to_vec(),
|
||||||
@ -721,7 +733,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn insert_and_unlock(tap: &Arc<AccountProvider>, acc: &str) -> Address {
|
fn insert_and_unlock(tap: &Arc<AccountProvider>, acc: &str) -> Address {
|
||||||
let addr = tap.insert_account(acc.sha3(), acc).unwrap();
|
let addr = tap.insert_account(Secret::from_slice(&acc.sha3()).unwrap(), acc).unwrap();
|
||||||
tap.unlock_account_permanently(addr, acc.into()).unwrap();
|
tap.unlock_account_permanently(addr, acc.into()).unwrap();
|
||||||
addr
|
addr
|
||||||
}
|
}
|
||||||
@ -825,7 +837,7 @@ mod tests {
|
|||||||
header.set_author(proposer);
|
header.set_author(proposer);
|
||||||
let mut seal = proposal_seal(&tap, &header, 0);
|
let mut seal = proposal_seal(&tap, &header, 0);
|
||||||
|
|
||||||
let vote_info = message_info_rlp(0, 0, Step::Precommit, Some(header.bare_hash()));
|
let vote_info = message_info_rlp(&VoteStep::new(0, 0, Step::Precommit), Some(header.bare_hash()));
|
||||||
let signature1 = tap.sign(proposer, None, vote_info.sha3()).unwrap();
|
let signature1 = tap.sign(proposer, None, vote_info.sha3()).unwrap();
|
||||||
|
|
||||||
seal[2] = ::rlp::encode(&vec![H520::from(signature1.clone())]).to_vec();
|
seal[2] = ::rlp::encode(&vec![H520::from(signature1.clone())]).to_vec();
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
use ethjson;
|
use ethjson;
|
||||||
use super::transition::TendermintTimeouts;
|
use super::transition::TendermintTimeouts;
|
||||||
use util::{U256, Uint};
|
use util::{U256, Uint, Address, FixedHash};
|
||||||
use time::Duration;
|
use time::Duration;
|
||||||
|
|
||||||
/// `Tendermint` params.
|
/// `Tendermint` params.
|
||||||
@ -32,6 +32,8 @@ pub struct TendermintParams {
|
|||||||
pub timeouts: TendermintTimeouts,
|
pub timeouts: TendermintTimeouts,
|
||||||
/// Block reward.
|
/// Block reward.
|
||||||
pub block_reward: U256,
|
pub block_reward: U256,
|
||||||
|
/// Namereg contract address.
|
||||||
|
pub registrar: Address,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_duration(ms: ethjson::uint::Uint) -> Duration {
|
fn to_duration(ms: ethjson::uint::Uint) -> Duration {
|
||||||
@ -52,6 +54,7 @@ impl From<ethjson::spec::TendermintParams> for TendermintParams {
|
|||||||
commit: p.timeout_commit.map_or(dt.commit, to_duration),
|
commit: p.timeout_commit.map_or(dt.commit, to_duration),
|
||||||
},
|
},
|
||||||
block_reward: p.block_reward.map_or_else(U256::zero, Into::into),
|
block_reward: p.block_reward.map_or_else(U256::zero, Into::into),
|
||||||
|
registrar: p.registrar.map_or_else(Address::new, Into::into),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,13 +17,50 @@
|
|||||||
//! Collects votes on hashes at each height and round.
|
//! Collects votes on hashes at each height and round.
|
||||||
|
|
||||||
use util::*;
|
use util::*;
|
||||||
use super::message::ConsensusMessage;
|
use super::message::*;
|
||||||
use super::{Height, Round, Step};
|
use super::{Height, Round, Step, BlockHash};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct VoteCollector {
|
pub struct VoteCollector {
|
||||||
/// Storing all Proposals, Prevotes and Precommits.
|
/// Storing all Proposals, Prevotes and Precommits.
|
||||||
votes: RwLock<BTreeMap<ConsensusMessage, Address>>,
|
votes: RwLock<BTreeMap<VoteStep, StepCollector>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct StepCollector {
|
||||||
|
voted: HashSet<Address>,
|
||||||
|
pub block_votes: HashMap<Option<BlockHash>, HashMap<H520, Address>>,
|
||||||
|
messages: HashSet<ConsensusMessage>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StepCollector {
|
||||||
|
/// Returns Some(&Address) when validator is double voting.
|
||||||
|
fn insert<'a>(&mut self, message: ConsensusMessage, address: &'a Address) -> Option<&'a Address> {
|
||||||
|
// Do nothing when message was seen.
|
||||||
|
if self.messages.insert(message.clone()) {
|
||||||
|
if self.voted.insert(address.clone()) {
|
||||||
|
self
|
||||||
|
.block_votes
|
||||||
|
.entry(message.block_hash)
|
||||||
|
.or_insert_with(HashMap::new)
|
||||||
|
.insert(message.signature, address.clone());
|
||||||
|
} else {
|
||||||
|
// Bad validator sent a different message.
|
||||||
|
return Some(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Count all votes for the given block hash at this step.
|
||||||
|
fn count_block(&self, block_hash: &Option<BlockHash>) -> usize {
|
||||||
|
self.block_votes.get(block_hash).map_or(0, HashMap::len)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Count all votes collected for the given step.
|
||||||
|
fn count(&self) -> usize {
|
||||||
|
self.block_votes.values().map(HashMap::len).sum()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -42,109 +79,105 @@ impl PartialEq for SealSignatures {
|
|||||||
impl Eq for SealSignatures {}
|
impl Eq for SealSignatures {}
|
||||||
|
|
||||||
impl VoteCollector {
|
impl VoteCollector {
|
||||||
pub fn new() -> VoteCollector {
|
pub fn new() -> Self {
|
||||||
let mut collector = BTreeMap::new();
|
let mut collector = BTreeMap::new();
|
||||||
// Insert dummy message to fulfill invariant: "only messages newer than the oldest are inserted".
|
// Insert dummy entry to fulfill invariant: "only messages newer than the oldest are inserted".
|
||||||
collector.insert(ConsensusMessage {
|
collector.insert(VoteStep::new(0, 0, Step::Propose), Default::default());
|
||||||
signature: H520::default(),
|
|
||||||
height: 0,
|
|
||||||
round: 0,
|
|
||||||
step: Step::Propose,
|
|
||||||
block_hash: None
|
|
||||||
},
|
|
||||||
Address::default());
|
|
||||||
VoteCollector { votes: RwLock::new(collector) }
|
VoteCollector { votes: RwLock::new(collector) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert vote if it is newer than the oldest one.
|
/// Insert vote if it is newer than the oldest one.
|
||||||
pub fn vote(&self, message: ConsensusMessage, voter: Address) -> Option<Address> {
|
pub fn vote<'a>(&self, message: ConsensusMessage, voter: &'a Address) -> Option<&'a Address> {
|
||||||
self.votes.write().insert(message, voter)
|
self
|
||||||
|
.votes
|
||||||
|
.write()
|
||||||
|
.entry(message.vote_step.clone())
|
||||||
|
.or_insert_with(Default::default)
|
||||||
|
.insert(message, voter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if the message should be ignored.
|
||||||
pub fn is_old_or_known(&self, message: &ConsensusMessage) -> bool {
|
pub fn is_old_or_known(&self, message: &ConsensusMessage) -> bool {
|
||||||
self.votes.read().get(message).map_or(false, |a| {
|
self
|
||||||
trace!(target: "poa", "Known message from {}: {:?}.", a, message);
|
.votes
|
||||||
true
|
.read()
|
||||||
}) || {
|
.get(&message.vote_step)
|
||||||
|
.map_or(false, |c| {
|
||||||
|
let is_known = c.messages.contains(message);
|
||||||
|
if is_known { trace!(target: "poa", "Known message: {:?}.", message); }
|
||||||
|
is_known
|
||||||
|
})
|
||||||
|
|| {
|
||||||
let guard = self.votes.read();
|
let guard = self.votes.read();
|
||||||
let is_old = guard.keys().next().map_or(true, |oldest| message <= oldest);
|
let is_old = guard.keys().next().map_or(true, |oldest| message.vote_step <= *oldest);
|
||||||
if is_old { trace!(target: "poa", "Old message {:?}.", message); }
|
if is_old { trace!(target: "poa", "Old message {:?}.", message); }
|
||||||
is_old
|
is_old
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Throws out messages older than message, leaves message as marker for the oldest.
|
/// Throws out messages older than message, leaves message as marker for the oldest.
|
||||||
pub fn throw_out_old(&self, message: &ConsensusMessage) {
|
pub fn throw_out_old(&self, vote_step: &VoteStep) {
|
||||||
let mut guard = self.votes.write();
|
let mut guard = self.votes.write();
|
||||||
let new_collector = guard.split_off(message);
|
let new_collector = guard.split_off(vote_step);
|
||||||
*guard = new_collector;
|
*guard = new_collector;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn seal_signatures(&self, height: Height, round: Round, block_hash: H256) -> Option<SealSignatures> {
|
/// Collects the signatures used to seal a block.
|
||||||
let bh = Some(block_hash);
|
pub fn seal_signatures(&self, height: Height, round: Round, block_hash: &H256) -> Option<SealSignatures> {
|
||||||
let (proposal, votes) = {
|
let ref bh = Some(*block_hash);
|
||||||
|
let precommit_step = VoteStep::new(height, round, Step::Precommit);
|
||||||
|
let maybe_seal = {
|
||||||
let guard = self.votes.read();
|
let guard = self.votes.read();
|
||||||
let mut current_signatures = guard.keys().skip_while(|m| !m.is_block_hash(height, round, Step::Propose, bh));
|
guard
|
||||||
let proposal = current_signatures.next().cloned();
|
.get(&VoteStep::new(height, round, Step::Propose))
|
||||||
let votes = current_signatures
|
.and_then(|c| c.block_votes.get(bh))
|
||||||
.skip_while(|m| !m.is_block_hash(height, round, Step::Precommit, bh))
|
.and_then(|proposals| proposals.keys().next())
|
||||||
.filter(|m| m.is_block_hash(height, round, Step::Precommit, bh))
|
.map(|proposal| SealSignatures {
|
||||||
.cloned()
|
proposal: proposal.clone(),
|
||||||
.collect::<Vec<_>>();
|
votes: guard
|
||||||
(proposal, votes)
|
.get(&precommit_step)
|
||||||
};
|
.and_then(|c| c.block_votes.get(bh))
|
||||||
if votes.is_empty() {
|
.map(|precommits| precommits.keys().cloned().collect())
|
||||||
return None;
|
.unwrap_or_else(Vec::new),
|
||||||
}
|
|
||||||
// Remove messages that are no longer relevant.
|
|
||||||
votes.last().map(|m| self.throw_out_old(m));
|
|
||||||
let mut votes_vec: Vec<_> = votes.into_iter().map(|m| m.signature).collect();
|
|
||||||
votes_vec.sort();
|
|
||||||
proposal.map(|p| SealSignatures {
|
|
||||||
proposal: p.signature,
|
|
||||||
votes: votes_vec,
|
|
||||||
})
|
})
|
||||||
|
.and_then(|seal| if seal.votes.is_empty() { None } else { Some(seal) })
|
||||||
|
};
|
||||||
|
if maybe_seal.is_some() {
|
||||||
|
// Remove messages that are no longer relevant.
|
||||||
|
self.throw_out_old(&precommit_step);
|
||||||
|
}
|
||||||
|
maybe_seal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Count votes which agree with the given message.
|
||||||
pub fn count_aligned_votes(&self, message: &ConsensusMessage) -> usize {
|
pub fn count_aligned_votes(&self, message: &ConsensusMessage) -> usize {
|
||||||
let guard = self.votes.read();
|
self
|
||||||
guard.keys()
|
.votes
|
||||||
.skip_while(|m| !m.is_aligned(message))
|
.read()
|
||||||
// sorted by signature so might not be continuous
|
.get(&message.vote_step)
|
||||||
.filter(|m| m.is_aligned(message))
|
.map_or(0, |m| m.count_block(&message.block_hash))
|
||||||
.count()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn count_step_votes(&self, height: Height, round: Round, step: Step) -> usize {
|
/// Count all votes collected for a given step.
|
||||||
let guard = self.votes.read();
|
pub fn count_step_votes(&self, vote_step: &VoteStep) -> usize {
|
||||||
let current = guard.iter().skip_while(|&(m, _)| !m.is_step(height, round, step));
|
self.votes.read().get(vote_step).map_or(0, StepCollector::count)
|
||||||
let mut origins = HashSet::new();
|
|
||||||
let mut n = 0;
|
|
||||||
for (message, origin) in current {
|
|
||||||
if message.is_step(height, round, step) {
|
|
||||||
if origins.insert(origin) {
|
|
||||||
n += 1;
|
|
||||||
} else {
|
|
||||||
warn!("count_step_votes: Authority {} has cast multiple step votes, this indicates malicious behaviour.", origin)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
n
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get all messages older than the height.
|
||||||
pub fn get_up_to(&self, height: Height) -> Vec<Bytes> {
|
pub fn get_up_to(&self, height: Height) -> Vec<Bytes> {
|
||||||
let guard = self.votes.read();
|
let guard = self.votes.read();
|
||||||
guard
|
guard
|
||||||
.keys()
|
.iter()
|
||||||
.filter(|m| m.step.is_pre())
|
.filter(|&(s, _)| s.step.is_pre())
|
||||||
.take_while(|m| m.height <= height)
|
.take_while(|&(s, _)| s.height <= height)
|
||||||
.map(|m| ::rlp::encode(m).to_vec())
|
.map(|(_, c)| c.messages.iter().map(|m| ::rlp::encode(m).to_vec()).collect::<Vec<_>>())
|
||||||
.collect()
|
.fold(Vec::new(), |mut acc, mut messages| { acc.append(&mut messages); acc })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieve address from which the message was sent from cache.
|
||||||
pub fn get(&self, message: &ConsensusMessage) -> Option<Address> {
|
pub fn get(&self, message: &ConsensusMessage) -> Option<Address> {
|
||||||
let guard = self.votes.read();
|
let guard = self.votes.read();
|
||||||
guard.get(message).cloned()
|
guard.get(&message.vote_step).and_then(|c| c.block_votes.get(&message.block_hash)).and_then(|origins| origins.get(&message.signature).cloned())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,15 +185,15 @@ impl VoteCollector {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use util::*;
|
use util::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
use super::super::{Height, Round, BlockHash, Step};
|
use super::super::{BlockHash, Step};
|
||||||
use super::super::message::ConsensusMessage;
|
use super::super::message::*;
|
||||||
|
|
||||||
fn random_vote(collector: &VoteCollector, signature: H520, h: Height, r: Round, step: Step, block_hash: Option<BlockHash>) -> Option<H160> {
|
fn random_vote(collector: &VoteCollector, signature: H520, vote_step: VoteStep, block_hash: Option<BlockHash>) -> bool {
|
||||||
full_vote(collector, signature, h, r, step, block_hash, H160::random())
|
full_vote(collector, signature, vote_step, block_hash, &H160::random()).is_none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn full_vote(collector: &VoteCollector, signature: H520, h: Height, r: Round, step: Step, block_hash: Option<BlockHash>, address: Address) -> Option<H160> {
|
fn full_vote<'a>(collector: &VoteCollector, signature: H520, vote_step: VoteStep, block_hash: Option<BlockHash>, address: &'a Address) -> Option<&'a Address> {
|
||||||
collector.vote(ConsensusMessage { signature: signature, height: h, round: r, step: step, block_hash: block_hash }, address)
|
collector.vote(ConsensusMessage { signature: signature, vote_step: vote_step, block_hash: block_hash }, address)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -173,68 +206,71 @@ mod tests {
|
|||||||
for _ in 0..5 {
|
for _ in 0..5 {
|
||||||
signatures.push(H520::random());
|
signatures.push(H520::random());
|
||||||
}
|
}
|
||||||
|
let propose_step = VoteStep::new(h, r, Step::Propose);
|
||||||
|
let prevote_step = VoteStep::new(h, r, Step::Prevote);
|
||||||
|
let precommit_step = VoteStep::new(h, r, Step::Precommit);
|
||||||
// Wrong height proposal.
|
// Wrong height proposal.
|
||||||
random_vote(&collector, signatures[4].clone(), h - 1, r, Step::Propose, bh.clone());
|
random_vote(&collector, signatures[4].clone(), VoteStep::new(h - 1, r, Step::Propose), bh.clone());
|
||||||
// Good proposal
|
// Good proposal
|
||||||
random_vote(&collector, signatures[0].clone(), h, r, Step::Propose, bh.clone());
|
random_vote(&collector, signatures[0].clone(), propose_step.clone(), bh.clone());
|
||||||
// Wrong block proposal.
|
// Wrong block proposal.
|
||||||
random_vote(&collector, signatures[0].clone(), h, r, Step::Propose, Some("0".sha3()));
|
random_vote(&collector, signatures[0].clone(), propose_step.clone(), Some("0".sha3()));
|
||||||
// Wrong block precommit.
|
// Wrong block precommit.
|
||||||
random_vote(&collector, signatures[3].clone(), h, r, Step::Precommit, Some("0".sha3()));
|
random_vote(&collector, signatures[3].clone(), precommit_step.clone(), Some("0".sha3()));
|
||||||
// Wrong round proposal.
|
// Wrong round proposal.
|
||||||
random_vote(&collector, signatures[0].clone(), h, r - 1, Step::Propose, bh.clone());
|
random_vote(&collector, signatures[0].clone(), VoteStep::new(h, r - 1, Step::Propose), bh.clone());
|
||||||
// Prevote.
|
// Prevote.
|
||||||
random_vote(&collector, signatures[0].clone(), h, r, Step::Prevote, bh.clone());
|
random_vote(&collector, signatures[0].clone(), prevote_step.clone(), bh.clone());
|
||||||
// Relevant precommit.
|
// Relevant precommit.
|
||||||
random_vote(&collector, signatures[2].clone(), h, r, Step::Precommit, bh.clone());
|
random_vote(&collector, signatures[2].clone(), precommit_step.clone(), bh.clone());
|
||||||
// Replcated vote.
|
// Replcated vote.
|
||||||
random_vote(&collector, signatures[2].clone(), h, r, Step::Precommit, bh.clone());
|
random_vote(&collector, signatures[2].clone(), precommit_step.clone(), bh.clone());
|
||||||
// Wrong round precommit.
|
// Wrong round precommit.
|
||||||
random_vote(&collector, signatures[4].clone(), h, r + 1, Step::Precommit, bh.clone());
|
random_vote(&collector, signatures[4].clone(), VoteStep::new(h, r + 1, Step::Precommit), bh.clone());
|
||||||
// Wrong height precommit.
|
// Wrong height precommit.
|
||||||
random_vote(&collector, signatures[3].clone(), h + 1, r, Step::Precommit, bh.clone());
|
random_vote(&collector, signatures[3].clone(), VoteStep::new(h + 1, r, Step::Precommit), bh.clone());
|
||||||
// Relevant precommit.
|
// Relevant precommit.
|
||||||
random_vote(&collector, signatures[1].clone(), h, r, Step::Precommit, bh.clone());
|
random_vote(&collector, signatures[1].clone(), precommit_step.clone(), bh.clone());
|
||||||
// Wrong round precommit, same signature.
|
// Wrong round precommit, same signature.
|
||||||
random_vote(&collector, signatures[1].clone(), h, r + 1, Step::Precommit, bh.clone());
|
random_vote(&collector, signatures[1].clone(), VoteStep::new(h, r + 1, Step::Precommit), bh.clone());
|
||||||
// Wrong round precommit.
|
// Wrong round precommit.
|
||||||
random_vote(&collector, signatures[4].clone(), h, r - 1, Step::Precommit, bh.clone());
|
random_vote(&collector, signatures[4].clone(), VoteStep::new(h, r - 1, Step::Precommit), bh.clone());
|
||||||
let seal = SealSignatures {
|
let seal = SealSignatures {
|
||||||
proposal: signatures[0],
|
proposal: signatures[0],
|
||||||
votes: signatures[1..3].to_vec()
|
votes: signatures[1..3].to_vec()
|
||||||
};
|
};
|
||||||
assert_eq!(seal, collector.seal_signatures(h, r, bh.unwrap()).unwrap());
|
assert_eq!(seal, collector.seal_signatures(h, r, &bh.unwrap()).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn count_votes() {
|
fn count_votes() {
|
||||||
let collector = VoteCollector::new();
|
let collector = VoteCollector::new();
|
||||||
|
let prevote_step = VoteStep::new(3, 2, Step::Prevote);
|
||||||
|
let precommit_step = VoteStep::new(3, 2, Step::Precommit);
|
||||||
// good prevote
|
// good prevote
|
||||||
random_vote(&collector, H520::random(), 3, 2, Step::Prevote, Some("0".sha3()));
|
random_vote(&collector, H520::random(), prevote_step.clone(), Some("0".sha3()));
|
||||||
random_vote(&collector, H520::random(), 3, 1, Step::Prevote, Some("0".sha3()));
|
random_vote(&collector, H520::random(), VoteStep::new(3, 1, Step::Prevote), Some("0".sha3()));
|
||||||
// good precommit
|
// good precommit
|
||||||
random_vote(&collector, H520::random(), 3, 2, Step::Precommit, Some("0".sha3()));
|
random_vote(&collector, H520::random(), precommit_step.clone(), Some("0".sha3()));
|
||||||
random_vote(&collector, H520::random(), 3, 3, Step::Precommit, Some("0".sha3()));
|
random_vote(&collector, H520::random(), VoteStep::new(3, 3, Step::Precommit), Some("0".sha3()));
|
||||||
// good prevote
|
// good prevote
|
||||||
random_vote(&collector, H520::random(), 3, 2, Step::Prevote, Some("1".sha3()));
|
random_vote(&collector, H520::random(), prevote_step.clone(), Some("1".sha3()));
|
||||||
// good prevote
|
// good prevote
|
||||||
let same_sig = H520::random();
|
let same_sig = H520::random();
|
||||||
random_vote(&collector, same_sig.clone(), 3, 2, Step::Prevote, Some("1".sha3()));
|
random_vote(&collector, same_sig.clone(), prevote_step.clone(), Some("1".sha3()));
|
||||||
random_vote(&collector, same_sig, 3, 2, Step::Prevote, Some("1".sha3()));
|
random_vote(&collector, same_sig, prevote_step.clone(), Some("1".sha3()));
|
||||||
// good precommit
|
// good precommit
|
||||||
random_vote(&collector, H520::random(), 3, 2, Step::Precommit, Some("1".sha3()));
|
random_vote(&collector, H520::random(), precommit_step.clone(), Some("1".sha3()));
|
||||||
// good prevote
|
// good prevote
|
||||||
random_vote(&collector, H520::random(), 3, 2, Step::Prevote, Some("0".sha3()));
|
random_vote(&collector, H520::random(), prevote_step.clone(), Some("0".sha3()));
|
||||||
random_vote(&collector, H520::random(), 2, 2, Step::Precommit, Some("2".sha3()));
|
random_vote(&collector, H520::random(), VoteStep::new(2, 2, Step::Precommit), Some("2".sha3()));
|
||||||
|
|
||||||
assert_eq!(collector.count_step_votes(3, 2, Step::Prevote), 4);
|
assert_eq!(collector.count_step_votes(&prevote_step), 4);
|
||||||
assert_eq!(collector.count_step_votes(3, 2, Step::Precommit), 2);
|
assert_eq!(collector.count_step_votes(&precommit_step), 2);
|
||||||
|
|
||||||
let message = ConsensusMessage {
|
let message = ConsensusMessage {
|
||||||
signature: H520::default(),
|
signature: H520::default(),
|
||||||
height: 3,
|
vote_step: prevote_step,
|
||||||
round: 2,
|
|
||||||
step: Step::Prevote,
|
|
||||||
block_hash: Some("1".sha3())
|
block_hash: Some("1".sha3())
|
||||||
};
|
};
|
||||||
assert_eq!(collector.count_aligned_votes(&message), 2);
|
assert_eq!(collector.count_aligned_votes(&message), 2);
|
||||||
@ -243,30 +279,29 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn remove_old() {
|
fn remove_old() {
|
||||||
let collector = VoteCollector::new();
|
let collector = VoteCollector::new();
|
||||||
random_vote(&collector, H520::random(), 3, 2, Step::Prevote, Some("0".sha3()));
|
let vote = |height, round, step, hash| {
|
||||||
random_vote(&collector, H520::random(), 3, 1, Step::Prevote, Some("0".sha3()));
|
random_vote(&collector, H520::random(), VoteStep::new(height, round, step), hash);
|
||||||
random_vote(&collector, H520::random(), 3, 3, Step::Precommit, Some("0".sha3()));
|
|
||||||
random_vote(&collector, H520::random(), 3, 2, Step::Prevote, Some("1".sha3()));
|
|
||||||
random_vote(&collector, H520::random(), 3, 2, Step::Prevote, Some("1".sha3()));
|
|
||||||
random_vote(&collector, H520::random(), 3, 2, Step::Prevote, Some("0".sha3()));
|
|
||||||
random_vote(&collector, H520::random(), 2, 2, Step::Precommit, Some("2".sha3()));
|
|
||||||
|
|
||||||
let message = ConsensusMessage {
|
|
||||||
signature: H520::default(),
|
|
||||||
height: 3,
|
|
||||||
round: 2,
|
|
||||||
step: Step::Precommit,
|
|
||||||
block_hash: Some("1".sha3())
|
|
||||||
};
|
};
|
||||||
collector.throw_out_old(&message);
|
vote(3, 2, Step::Prevote, Some("0".sha3()));
|
||||||
|
vote(3, 1, Step::Prevote, Some("0".sha3()));
|
||||||
|
vote(3, 3, Step::Precommit, Some("0".sha3()));
|
||||||
|
vote(3, 2, Step::Prevote, Some("1".sha3()));
|
||||||
|
vote(3, 2, Step::Prevote, Some("1".sha3()));
|
||||||
|
vote(3, 2, Step::Prevote, Some("0".sha3()));
|
||||||
|
vote(2, 2, Step::Precommit, Some("2".sha3()));
|
||||||
|
|
||||||
|
collector.throw_out_old(&VoteStep::new(3, 2, Step::Precommit));
|
||||||
assert_eq!(collector.votes.read().len(), 1);
|
assert_eq!(collector.votes.read().len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn malicious_authority() {
|
fn malicious_authority() {
|
||||||
let collector = VoteCollector::new();
|
let collector = VoteCollector::new();
|
||||||
full_vote(&collector, H520::random(), 3, 2, Step::Prevote, Some("0".sha3()), Address::default());
|
let vote_step = VoteStep::new(3, 2, Step::Prevote);
|
||||||
full_vote(&collector, H520::random(), 3, 2, Step::Prevote, Some("1".sha3()), Address::default());
|
// Vote is inserted fine.
|
||||||
assert_eq!(collector.count_step_votes(3, 2, Step::Prevote), 1);
|
assert!(full_vote(&collector, H520::random(), vote_step.clone(), Some("0".sha3()), &Address::default()).is_none());
|
||||||
|
// Returns the double voting address.
|
||||||
|
full_vote(&collector, H520::random(), vote_step.clone(), Some("1".sha3()), &Address::default()).unwrap();
|
||||||
|
assert_eq!(collector.count_step_votes(&vote_step), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,6 +140,7 @@ mod tests {
|
|||||||
use account_provider::AccountProvider;
|
use account_provider::AccountProvider;
|
||||||
use transaction::{Transaction, Action};
|
use transaction::{Transaction, Action};
|
||||||
use client::{BlockChainClient, EngineClient};
|
use client::{BlockChainClient, EngineClient};
|
||||||
|
use ethkey::Secret;
|
||||||
use miner::MinerService;
|
use miner::MinerService;
|
||||||
use tests::helpers::generate_dummy_client_with_spec_and_data;
|
use tests::helpers::generate_dummy_client_with_spec_and_data;
|
||||||
use super::super::ValidatorSet;
|
use super::super::ValidatorSet;
|
||||||
@ -158,8 +159,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn changes_validators() {
|
fn changes_validators() {
|
||||||
let tap = Arc::new(AccountProvider::transient_provider());
|
let tap = Arc::new(AccountProvider::transient_provider());
|
||||||
let v0 = tap.insert_account("1".sha3(), "").unwrap();
|
let s0 = Secret::from_slice(&"1".sha3()).unwrap();
|
||||||
let v1 = tap.insert_account("0".sha3(), "").unwrap();
|
let v0 = tap.insert_account(s0.clone(), "").unwrap();
|
||||||
|
let v1 = tap.insert_account(Secret::from_slice(&"0".sha3()).unwrap(), "").unwrap();
|
||||||
let spec_factory = || {
|
let spec_factory = || {
|
||||||
let spec = Spec::new_validator_contract();
|
let spec = Spec::new_validator_contract();
|
||||||
spec.engine.register_account_provider(tap.clone());
|
spec.engine.register_account_provider(tap.clone());
|
||||||
@ -178,7 +180,7 @@ mod tests {
|
|||||||
action: Action::Call(validator_contract),
|
action: Action::Call(validator_contract),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
data: "f94e18670000000000000000000000000000000000000000000000000000000000000001".from_hex().unwrap(),
|
data: "f94e18670000000000000000000000000000000000000000000000000000000000000001".from_hex().unwrap(),
|
||||||
}.sign(&"1".sha3(), None);
|
}.sign(&s0, None);
|
||||||
client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap();
|
client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap();
|
||||||
client.update_sealing();
|
client.update_sealing();
|
||||||
assert_eq!(client.chain_info().best_block_number, 1);
|
assert_eq!(client.chain_info().best_block_number, 1);
|
||||||
@ -190,7 +192,7 @@ mod tests {
|
|||||||
action: Action::Call(validator_contract),
|
action: Action::Call(validator_contract),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
data: "4d238c8e00000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1".from_hex().unwrap(),
|
data: "4d238c8e00000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1".from_hex().unwrap(),
|
||||||
}.sign(&"1".sha3(), None);
|
}.sign(&s0, None);
|
||||||
client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap();
|
client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap();
|
||||||
client.update_sealing();
|
client.update_sealing();
|
||||||
// The transaction is not yet included so still unable to seal.
|
// The transaction is not yet included so still unable to seal.
|
||||||
@ -209,7 +211,7 @@ mod tests {
|
|||||||
action: Action::Call(Address::default()),
|
action: Action::Call(Address::default()),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
data: Vec::new(),
|
data: Vec::new(),
|
||||||
}.sign(&"1".sha3(), None);
|
}.sign(&s0, None);
|
||||||
client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap();
|
client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap();
|
||||||
client.update_sealing();
|
client.update_sealing();
|
||||||
// Able to seal again.
|
// Able to seal again.
|
||||||
|
@ -31,6 +31,9 @@ use ethjson;
|
|||||||
use rlp::{self, UntrustedRlp, View};
|
use rlp::{self, UntrustedRlp, View};
|
||||||
use blockchain::extras::BlockDetails;
|
use blockchain::extras::BlockDetails;
|
||||||
|
|
||||||
|
/// Parity tries to round block.gas_limit to multiple of this constant
|
||||||
|
pub const PARITY_GAS_LIMIT_DETERMINANT: U256 = U256([37, 0, 0, 0]);
|
||||||
|
|
||||||
/// Ethash params.
|
/// Ethash params.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct EthashParams {
|
pub struct EthashParams {
|
||||||
@ -180,14 +183,23 @@ impl Engine for Ethash {
|
|||||||
let bound_divisor = self.ethash_params.gas_limit_bound_divisor;
|
let bound_divisor = self.ethash_params.gas_limit_bound_divisor;
|
||||||
let lower_limit = gas_limit - gas_limit / bound_divisor + 1.into();
|
let lower_limit = gas_limit - gas_limit / bound_divisor + 1.into();
|
||||||
let upper_limit = gas_limit + gas_limit / bound_divisor - 1.into();
|
let upper_limit = gas_limit + gas_limit / bound_divisor - 1.into();
|
||||||
if gas_limit < gas_floor_target {
|
let gas_limit = if gas_limit < gas_floor_target {
|
||||||
min(gas_floor_target, upper_limit)
|
let gas_limit = min(gas_floor_target, upper_limit);
|
||||||
|
round_block_gas_limit(gas_limit, lower_limit, upper_limit)
|
||||||
} else if gas_limit > gas_ceil_target {
|
} else if gas_limit > gas_ceil_target {
|
||||||
max(gas_ceil_target, lower_limit)
|
let gas_limit = max(gas_ceil_target, lower_limit);
|
||||||
|
round_block_gas_limit(gas_limit, lower_limit, upper_limit)
|
||||||
} else {
|
} else {
|
||||||
max(gas_floor_target, min(min(gas_ceil_target, upper_limit),
|
let total_lower_limit = max(lower_limit, gas_floor_target);
|
||||||
lower_limit + (header.gas_used().clone() * 6.into() / 5.into()) / bound_divisor))
|
let total_upper_limit = min(upper_limit, gas_ceil_target);
|
||||||
}
|
let gas_limit = max(gas_floor_target, min(total_upper_limit,
|
||||||
|
lower_limit + (header.gas_used().clone() * 6.into() / 5.into()) / bound_divisor));
|
||||||
|
round_block_gas_limit(gas_limit, total_lower_limit, total_upper_limit)
|
||||||
|
};
|
||||||
|
// ensure that we are not violating protocol limits
|
||||||
|
debug_assert!(gas_limit >= lower_limit);
|
||||||
|
debug_assert!(gas_limit <= upper_limit);
|
||||||
|
gas_limit
|
||||||
};
|
};
|
||||||
header.set_difficulty(difficulty);
|
header.set_difficulty(difficulty);
|
||||||
header.set_gas_limit(gas_limit);
|
header.set_gas_limit(gas_limit);
|
||||||
@ -338,6 +350,23 @@ pub fn is_new_best_block(best_total_difficulty: U256, parent_details: &BlockDeta
|
|||||||
parent_details.total_difficulty + new_header.difficulty() > best_total_difficulty
|
parent_details.total_difficulty + new_header.difficulty() > best_total_difficulty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to round gas_limit a bit so that:
|
||||||
|
// 1) it will still be in desired range
|
||||||
|
// 2) it will be a nearest (with tendency to increase) multiple of PARITY_GAS_LIMIT_DETERMINANT
|
||||||
|
fn round_block_gas_limit(gas_limit: U256, lower_limit: U256, upper_limit: U256) -> U256 {
|
||||||
|
let increased_gas_limit = gas_limit + (PARITY_GAS_LIMIT_DETERMINANT - gas_limit % PARITY_GAS_LIMIT_DETERMINANT);
|
||||||
|
if increased_gas_limit > upper_limit {
|
||||||
|
let decreased_gas_limit = increased_gas_limit - PARITY_GAS_LIMIT_DETERMINANT;
|
||||||
|
if decreased_gas_limit < lower_limit {
|
||||||
|
gas_limit
|
||||||
|
} else {
|
||||||
|
decreased_gas_limit
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
increased_gas_limit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature="dev", allow(wrong_self_convention))]
|
#[cfg_attr(feature="dev", allow(wrong_self_convention))]
|
||||||
impl Ethash {
|
impl Ethash {
|
||||||
fn calculate_difficulty(&self, header: &Header, parent: &Header) -> U256 {
|
fn calculate_difficulty(&self, header: &Header, parent: &Header) -> U256 {
|
||||||
@ -435,11 +464,12 @@ mod tests {
|
|||||||
use util::*;
|
use util::*;
|
||||||
use block::*;
|
use block::*;
|
||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
|
use engines::Engine;
|
||||||
use env_info::EnvInfo;
|
use env_info::EnvInfo;
|
||||||
use error::{BlockError, Error};
|
use error::{BlockError, Error};
|
||||||
use header::Header;
|
use header::Header;
|
||||||
use super::super::{new_morden, new_homestead_test};
|
use super::super::{new_morden, new_homestead_test};
|
||||||
use super::{Ethash, EthashParams};
|
use super::{Ethash, EthashParams, PARITY_GAS_LIMIT_DETERMINANT};
|
||||||
use rlp;
|
use rlp;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -777,4 +807,65 @@ mod tests {
|
|||||||
ethash.calculate_difficulty(&header, &parent_header)
|
ethash.calculate_difficulty(&header, &parent_header)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gas_limit_is_multiple_of_determinant() {
|
||||||
|
let spec = new_homestead_test();
|
||||||
|
let ethash = Ethash::new(spec.params, get_default_ethash_params(), BTreeMap::new());
|
||||||
|
let mut parent = Header::new();
|
||||||
|
let mut header = Header::new();
|
||||||
|
header.set_number(1);
|
||||||
|
|
||||||
|
// this test will work for this constant only
|
||||||
|
assert_eq!(PARITY_GAS_LIMIT_DETERMINANT, U256::from(37));
|
||||||
|
|
||||||
|
// when parent.gas_limit < gas_floor_target:
|
||||||
|
parent.set_gas_limit(U256::from(50_000));
|
||||||
|
ethash.populate_from_parent(&mut header, &parent, U256::from(100_000), U256::from(200_000));
|
||||||
|
assert_eq!(*header.gas_limit(), U256::from(50_024));
|
||||||
|
|
||||||
|
// when parent.gas_limit > gas_ceil_target:
|
||||||
|
parent.set_gas_limit(U256::from(250_000));
|
||||||
|
ethash.populate_from_parent(&mut header, &parent, U256::from(100_000), U256::from(200_000));
|
||||||
|
assert_eq!(*header.gas_limit(), U256::from(249_787));
|
||||||
|
|
||||||
|
// when parent.gas_limit is in miner's range
|
||||||
|
header.set_gas_used(U256::from(150_000));
|
||||||
|
parent.set_gas_limit(U256::from(150_000));
|
||||||
|
ethash.populate_from_parent(&mut header, &parent, U256::from(100_000), U256::from(200_000));
|
||||||
|
assert_eq!(*header.gas_limit(), U256::from(150_035));
|
||||||
|
|
||||||
|
// when parent.gas_limit is in miner's range
|
||||||
|
// && we can NOT increase it to be multiple of constant
|
||||||
|
header.set_gas_used(U256::from(150_000));
|
||||||
|
parent.set_gas_limit(U256::from(150_000));
|
||||||
|
ethash.populate_from_parent(&mut header, &parent, U256::from(100_000), U256::from(150_002));
|
||||||
|
assert_eq!(*header.gas_limit(), U256::from(149_998));
|
||||||
|
|
||||||
|
// when parent.gas_limit is in miner's range
|
||||||
|
// && we can NOT increase it to be multiple of constant
|
||||||
|
// && we can NOT decrease it to be multiple of constant
|
||||||
|
header.set_gas_used(U256::from(150_000));
|
||||||
|
parent.set_gas_limit(U256::from(150_000));
|
||||||
|
ethash.populate_from_parent(&mut header, &parent, U256::from(150_000), U256::from(150_002));
|
||||||
|
assert_eq!(*header.gas_limit(), U256::from(150_002));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn difficulty_max_timestamp() {
|
||||||
|
let spec = new_homestead_test();
|
||||||
|
let ethparams = get_default_ethash_params();
|
||||||
|
let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new());
|
||||||
|
|
||||||
|
let mut parent_header = Header::default();
|
||||||
|
parent_header.set_number(1000000);
|
||||||
|
parent_header.set_difficulty(U256::from_str("b69de81a22b").unwrap());
|
||||||
|
parent_header.set_timestamp(1455404053);
|
||||||
|
let mut header = Header::default();
|
||||||
|
header.set_number(parent_header.number() + 1);
|
||||||
|
header.set_timestamp(u64::max_value());
|
||||||
|
|
||||||
|
let difficulty = ethash.calculate_difficulty(&header, &parent_header);
|
||||||
|
assert_eq!(U256::from(12543204905719u64), difficulty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,46 +30,52 @@ pub use self::denominations::*;
|
|||||||
use super::spec::*;
|
use super::spec::*;
|
||||||
|
|
||||||
/// Most recent fork block that we support on Mainnet.
|
/// Most recent fork block that we support on Mainnet.
|
||||||
pub const FORK_SUPPORTED_FRONTIER: u64 = 2675000;
|
pub const FORK_SUPPORTED_FOUNDATION: u64 = 2675000;
|
||||||
|
|
||||||
/// Most recent fork block that we support on Ropsten.
|
/// Most recent fork block that we support on Ropsten.
|
||||||
pub const FORK_SUPPORTED_ROPSTEN: u64 = 10;
|
pub const FORK_SUPPORTED_ROPSTEN: u64 = 10;
|
||||||
|
|
||||||
|
/// Most recent fork block that we support on Kovan.
|
||||||
|
pub const FORK_SUPPORTED_KOVAN: u64 = 0;
|
||||||
|
|
||||||
fn load(b: &[u8]) -> Spec {
|
fn load(b: &[u8]) -> Spec {
|
||||||
Spec::load(b).expect("chain spec is invalid")
|
Spec::load(b).expect("chain spec is invalid")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new Olympic chain spec.
|
/// Create a new Foundation Olympic chain spec.
|
||||||
pub fn new_olympic() -> Spec { load(include_bytes!("../../res/ethereum/olympic.json")) }
|
pub fn new_olympic() -> Spec { load(include_bytes!("../../res/ethereum/olympic.json")) }
|
||||||
|
|
||||||
/// Create a new Frontier mainnet chain spec.
|
/// Create a new Foundation Mainnet chain spec.
|
||||||
pub fn new_frontier() -> Spec { load(include_bytes!("../../res/ethereum/frontier.json")) }
|
pub fn new_foundation() -> Spec { load(include_bytes!("../../res/ethereum/foundation.json")) }
|
||||||
|
|
||||||
/// Create a new Frontier mainnet chain spec without the DAO hardfork.
|
/// Create a new Classic Mainnet chain spec without the DAO hardfork.
|
||||||
pub fn new_classic() -> Spec { load(include_bytes!("../../res/ethereum/classic.json")) }
|
pub fn new_classic() -> Spec { load(include_bytes!("../../res/ethereum/classic.json")) }
|
||||||
|
|
||||||
/// Create a new Frontier mainnet chain spec without the DAO hardfork.
|
/// Create a new Expanse mainnet chain spec.
|
||||||
pub fn new_expanse() -> Spec { load(include_bytes!("../../res/ethereum/expanse.json")) }
|
pub fn new_expanse() -> Spec { load(include_bytes!("../../res/ethereum/expanse.json")) }
|
||||||
|
|
||||||
/// Create a new Frontier chain spec as though it never changes to Homestead.
|
/// Create a new Kovan testnet chain spec.
|
||||||
|
pub fn new_kovan() -> Spec { load(include_bytes!("../../res/ethereum/kovan.json")) }
|
||||||
|
|
||||||
|
/// Create a new Foundation Frontier-era chain spec as though it never changes to Homestead.
|
||||||
pub fn new_frontier_test() -> Spec { load(include_bytes!("../../res/ethereum/frontier_test.json")) }
|
pub fn new_frontier_test() -> Spec { load(include_bytes!("../../res/ethereum/frontier_test.json")) }
|
||||||
|
|
||||||
/// Create a new Homestead chain spec as though it never changed from Frontier.
|
/// Create a new Foundation Homestead-era chain spec as though it never changed from Frontier.
|
||||||
pub fn new_homestead_test() -> Spec { load(include_bytes!("../../res/ethereum/homestead_test.json")) }
|
pub fn new_homestead_test() -> Spec { load(include_bytes!("../../res/ethereum/homestead_test.json")) }
|
||||||
|
|
||||||
/// Create a new Homestead-EIP150 chain spec as though it never changed from Homestead/Frontier.
|
/// Create a new Foundation Homestead-EIP150-era chain spec as though it never changed from Homestead/Frontier.
|
||||||
pub fn new_eip150_test() -> Spec { load(include_bytes!("../../res/ethereum/eip150_test.json")) }
|
pub fn new_eip150_test() -> Spec { load(include_bytes!("../../res/ethereum/eip150_test.json")) }
|
||||||
|
|
||||||
/// Create a new Homestead-EIP150 chain spec as though it never changed from Homestead/Frontier.
|
/// Create a new Foundation Homestead-EIP161-era chain spec as though it never changed from Homestead/Frontier.
|
||||||
pub fn new_eip161_test() -> Spec { load(include_bytes!("../../res/ethereum/eip161_test.json")) }
|
pub fn new_eip161_test() -> Spec { load(include_bytes!("../../res/ethereum/eip161_test.json")) }
|
||||||
|
|
||||||
/// Create a new Frontier/Homestead/DAO chain spec with transition points at #5 and #8.
|
/// Create a new Foundation Frontier/Homestead/DAO chain spec with transition points at #5 and #8.
|
||||||
pub fn new_transition_test() -> Spec { load(include_bytes!("../../res/ethereum/transition_test.json")) }
|
pub fn new_transition_test() -> Spec { load(include_bytes!("../../res/ethereum/transition_test.json")) }
|
||||||
|
|
||||||
/// Create a new Frontier main net chain spec without genesis accounts.
|
/// Create a new Foundation Mainnet chain spec without genesis accounts.
|
||||||
pub fn new_mainnet_like() -> Spec { load(include_bytes!("../../res/ethereum/frontier_like_test.json")) }
|
pub fn new_mainnet_like() -> Spec { load(include_bytes!("../../res/ethereum/frontier_like_test.json")) }
|
||||||
|
|
||||||
/// Create a new Ropsten chain spec.
|
/// Create a new Foundation Ropsten chain spec.
|
||||||
pub fn new_ropsten() -> Spec { load(include_bytes!("../../res/ethereum/ropsten.json")) }
|
pub fn new_ropsten() -> Spec { load(include_bytes!("../../res/ethereum/ropsten.json")) }
|
||||||
|
|
||||||
/// Create a new Morden chain spec.
|
/// Create a new Morden chain spec.
|
||||||
@ -112,7 +118,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn frontier() {
|
fn frontier() {
|
||||||
let frontier = new_frontier();
|
let frontier = new_foundation();
|
||||||
|
|
||||||
assert_eq!(frontier.state_root(), "d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544".into());
|
assert_eq!(frontier.state_root(), "d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544".into());
|
||||||
let genesis = frontier.genesis_block();
|
let genesis = frontier.genesis_block();
|
||||||
|
@ -22,7 +22,7 @@ use action_params::ActionParams;
|
|||||||
use evm::Ext;
|
use evm::Ext;
|
||||||
|
|
||||||
/// Evm errors.
|
/// Evm errors.
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// `OutOfGas` is returned when transaction execution runs out of gas.
|
/// `OutOfGas` is returned when transaction execution runs out of gas.
|
||||||
/// The state should be reverted to the state from before the
|
/// The state should be reverted to the state from before the
|
||||||
|
@ -37,7 +37,6 @@ use bit_set::BitSet;
|
|||||||
|
|
||||||
use util::*;
|
use util::*;
|
||||||
|
|
||||||
type CodePosition = usize;
|
|
||||||
type ProgramCounter = usize;
|
type ProgramCounter = usize;
|
||||||
|
|
||||||
const ONE: U256 = U256([1, 0, 0, 0]);
|
const ONE: U256 = U256([1, 0, 0, 0]);
|
||||||
|
@ -45,7 +45,7 @@ pub fn contract_address(address: &Address, nonce: &U256) -> Address {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Transaction execution options.
|
/// Transaction execution options.
|
||||||
#[derive(Default)]
|
#[derive(Default, Copy, Clone, PartialEq)]
|
||||||
pub struct TransactOptions {
|
pub struct TransactOptions {
|
||||||
/// Enable call tracing.
|
/// Enable call tracing.
|
||||||
pub tracing: bool,
|
pub tracing: bool,
|
||||||
@ -463,8 +463,9 @@ impl<'a> Executive<'a> {
|
|||||||
|
|
||||||
match result {
|
match result {
|
||||||
Err(evm::Error::Internal) => Err(ExecutionError::Internal),
|
Err(evm::Error::Internal) => Err(ExecutionError::Internal),
|
||||||
Err(_) => {
|
Err(exception) => {
|
||||||
Ok(Executed {
|
Ok(Executed {
|
||||||
|
exception: Some(exception),
|
||||||
gas: t.gas,
|
gas: t.gas,
|
||||||
gas_used: t.gas,
|
gas_used: t.gas,
|
||||||
refunded: U256::zero(),
|
refunded: U256::zero(),
|
||||||
@ -479,6 +480,7 @@ impl<'a> Executive<'a> {
|
|||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
Ok(Executed {
|
Ok(Executed {
|
||||||
|
exception: None,
|
||||||
gas: t.gas,
|
gas: t.gas,
|
||||||
gas_used: gas_used,
|
gas_used: gas_used,
|
||||||
refunded: refunded,
|
refunded: refunded,
|
||||||
|
@ -276,7 +276,7 @@ impl Decodable for Header {
|
|||||||
number: r.val_at(8)?,
|
number: r.val_at(8)?,
|
||||||
gas_limit: r.val_at(9)?,
|
gas_limit: r.val_at(9)?,
|
||||||
gas_used: r.val_at(10)?,
|
gas_used: r.val_at(10)?,
|
||||||
timestamp: r.val_at(11)?,
|
timestamp: min(r.val_at::<U256>(11)?, u64::max_value().into()).as_u64(),
|
||||||
extra_data: r.val_at(12)?,
|
extra_data: r.val_at(12)?,
|
||||||
seal: vec![],
|
seal: vec![],
|
||||||
hash: RefCell::new(Some(r.as_raw().sha3())),
|
hash: RefCell::new(Some(r.as_raw().sha3())),
|
||||||
|
@ -22,7 +22,7 @@ use std::ops::{Deref, DerefMut};
|
|||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use transaction::{SignedTransaction, Action};
|
use transaction::{SignedTransaction, Action};
|
||||||
use transient_hashmap::TransientHashMap;
|
use transient_hashmap::TransientHashMap;
|
||||||
use miner::{TransactionQueue, TransactionImportResult, TransactionOrigin, AccountDetails};
|
use miner::{TransactionQueue, TransactionQueueDetailsProvider, TransactionImportResult, TransactionOrigin};
|
||||||
use miner::transaction_queue::QueuingInstant;
|
use miner::transaction_queue::QueuingInstant;
|
||||||
use error::{Error, TransactionError};
|
use error::{Error, TransactionError};
|
||||||
use util::{Uint, U256, H256, Address, Hashable};
|
use util::{Uint, U256, H256, Address, Hashable};
|
||||||
@ -76,16 +76,12 @@ impl BanningTransactionQueue {
|
|||||||
|
|
||||||
/// Add to the queue taking bans into consideration.
|
/// Add to the queue taking bans into consideration.
|
||||||
/// May reject transaction because of the banlist.
|
/// May reject transaction because of the banlist.
|
||||||
pub fn add_with_banlist<F, G>(
|
pub fn add_with_banlist(
|
||||||
&mut self,
|
&mut self,
|
||||||
transaction: SignedTransaction,
|
transaction: SignedTransaction,
|
||||||
time: QueuingInstant,
|
time: QueuingInstant,
|
||||||
account_details: &F,
|
details_provider: &TransactionQueueDetailsProvider,
|
||||||
gas_estimator: &G,
|
) -> Result<TransactionImportResult, Error> {
|
||||||
) -> Result<TransactionImportResult, Error> where
|
|
||||||
F: Fn(&Address) -> AccountDetails,
|
|
||||||
G: Fn(&SignedTransaction) -> U256,
|
|
||||||
{
|
|
||||||
if let Threshold::BanAfter(threshold) = self.ban_threshold {
|
if let Threshold::BanAfter(threshold) = self.ban_threshold {
|
||||||
// NOTE In all checks use direct query to avoid increasing ban timeout.
|
// NOTE In all checks use direct query to avoid increasing ban timeout.
|
||||||
|
|
||||||
@ -117,7 +113,7 @@ impl BanningTransactionQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.queue.add(transaction, TransactionOrigin::External, time, None, account_details, gas_estimator)
|
self.queue.add(transaction, TransactionOrigin::External, time, None, details_provider)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ban transaction with given hash.
|
/// Ban transaction with given hash.
|
||||||
@ -220,22 +216,16 @@ mod tests {
|
|||||||
use transaction::{Transaction, SignedTransaction, Action};
|
use transaction::{Transaction, SignedTransaction, Action};
|
||||||
use error::{Error, TransactionError};
|
use error::{Error, TransactionError};
|
||||||
use client::TransactionImportResult;
|
use client::TransactionImportResult;
|
||||||
use miner::{TransactionQueue, TransactionOrigin, AccountDetails};
|
use miner::{TransactionQueue, TransactionOrigin};
|
||||||
use util::{Uint, U256, Address, FromHex, Hashable};
|
use util::{Uint, U256, Address, FromHex, Hashable};
|
||||||
|
use miner::transaction_queue::test::DummyTransactionDetailsProvider;
|
||||||
|
|
||||||
fn queue() -> BanningTransactionQueue {
|
fn queue() -> BanningTransactionQueue {
|
||||||
BanningTransactionQueue::new(TransactionQueue::default(), Threshold::BanAfter(1), Duration::from_secs(180))
|
BanningTransactionQueue::new(TransactionQueue::default(), Threshold::BanAfter(1), Duration::from_secs(180))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_account_details(_address: &Address) -> AccountDetails {
|
fn default_tx_provider() -> DummyTransactionDetailsProvider {
|
||||||
AccountDetails {
|
DummyTransactionDetailsProvider::default().with_account_nonce(U256::zero())
|
||||||
nonce: U256::zero(),
|
|
||||||
balance: !U256::zero(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gas_required(_tx: &SignedTransaction) -> U256 {
|
|
||||||
0.into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transaction(action: Action) -> SignedTransaction {
|
fn transaction(action: Action) -> SignedTransaction {
|
||||||
@ -265,7 +255,7 @@ mod tests {
|
|||||||
let mut txq = queue();
|
let mut txq = queue();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
txq.queue().add(tx, TransactionOrigin::External, 0, None, &default_account_details, &gas_required).unwrap();
|
txq.queue().add(tx, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
// should also deref to queue
|
// should also deref to queue
|
||||||
@ -281,12 +271,12 @@ mod tests {
|
|||||||
let banlist1 = txq.ban_sender(tx.sender().unwrap());
|
let banlist1 = txq.ban_sender(tx.sender().unwrap());
|
||||||
assert!(!banlist1, "Threshold not reached yet.");
|
assert!(!banlist1, "Threshold not reached yet.");
|
||||||
// Insert once
|
// Insert once
|
||||||
let import1 = txq.add_with_banlist(tx.clone(), 0, &default_account_details, &gas_required).unwrap();
|
let import1 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider()).unwrap();
|
||||||
assert_eq!(import1, TransactionImportResult::Current);
|
assert_eq!(import1, TransactionImportResult::Current);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let banlist2 = txq.ban_sender(tx.sender().unwrap());
|
let banlist2 = txq.ban_sender(tx.sender().unwrap());
|
||||||
let import2 = txq.add_with_banlist(tx.clone(), 0, &default_account_details, &gas_required);
|
let import2 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert!(banlist2, "Threshold should be reached - banned.");
|
assert!(banlist2, "Threshold should be reached - banned.");
|
||||||
@ -305,12 +295,12 @@ mod tests {
|
|||||||
let banlist1 = txq.ban_recipient(recipient);
|
let banlist1 = txq.ban_recipient(recipient);
|
||||||
assert!(!banlist1, "Threshold not reached yet.");
|
assert!(!banlist1, "Threshold not reached yet.");
|
||||||
// Insert once
|
// Insert once
|
||||||
let import1 = txq.add_with_banlist(tx.clone(), 0, &default_account_details, &gas_required).unwrap();
|
let import1 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider()).unwrap();
|
||||||
assert_eq!(import1, TransactionImportResult::Current);
|
assert_eq!(import1, TransactionImportResult::Current);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let banlist2 = txq.ban_recipient(recipient);
|
let banlist2 = txq.ban_recipient(recipient);
|
||||||
let import2 = txq.add_with_banlist(tx.clone(), 0, &default_account_details, &gas_required);
|
let import2 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert!(banlist2, "Threshold should be reached - banned.");
|
assert!(banlist2, "Threshold should be reached - banned.");
|
||||||
@ -327,12 +317,12 @@ mod tests {
|
|||||||
let banlist1 = txq.ban_codehash(codehash);
|
let banlist1 = txq.ban_codehash(codehash);
|
||||||
assert!(!banlist1, "Threshold not reached yet.");
|
assert!(!banlist1, "Threshold not reached yet.");
|
||||||
// Insert once
|
// Insert once
|
||||||
let import1 = txq.add_with_banlist(tx.clone(), 0, &default_account_details, &gas_required).unwrap();
|
let import1 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider()).unwrap();
|
||||||
assert_eq!(import1, TransactionImportResult::Current);
|
assert_eq!(import1, TransactionImportResult::Current);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let banlist2 = txq.ban_codehash(codehash);
|
let banlist2 = txq.ban_codehash(codehash);
|
||||||
let import2 = txq.add_with_banlist(tx.clone(), 0, &default_account_details, &gas_required);
|
let import2 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert!(banlist2, "Threshold should be reached - banned.");
|
assert!(banlist2, "Threshold should be reached - banned.");
|
||||||
|
@ -70,36 +70,43 @@ impl LocalTransactionsList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_pending(&mut self, hash: H256) {
|
pub fn mark_pending(&mut self, hash: H256) {
|
||||||
|
debug!(target: "own_tx", "Imported to Current (hash {:?})", hash);
|
||||||
self.clear_old();
|
self.clear_old();
|
||||||
self.transactions.insert(hash, Status::Pending);
|
self.transactions.insert(hash, Status::Pending);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_future(&mut self, hash: H256) {
|
pub fn mark_future(&mut self, hash: H256) {
|
||||||
|
debug!(target: "own_tx", "Imported to Future (hash {:?})", hash);
|
||||||
self.transactions.insert(hash, Status::Future);
|
self.transactions.insert(hash, Status::Future);
|
||||||
self.clear_old();
|
self.clear_old();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_rejected(&mut self, tx: SignedTransaction, err: TransactionError) {
|
pub fn mark_rejected(&mut self, tx: SignedTransaction, err: TransactionError) {
|
||||||
|
debug!(target: "own_tx", "Transaction rejected (hash {:?}): {:?}", tx.hash(), err);
|
||||||
self.transactions.insert(tx.hash(), Status::Rejected(tx, err));
|
self.transactions.insert(tx.hash(), Status::Rejected(tx, err));
|
||||||
self.clear_old();
|
self.clear_old();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_replaced(&mut self, tx: SignedTransaction, gas_price: U256, hash: H256) {
|
pub fn mark_replaced(&mut self, tx: SignedTransaction, gas_price: U256, hash: H256) {
|
||||||
|
debug!(target: "own_tx", "Transaction replaced (hash {:?}) by {:?} (new gas price: {:?})", tx.hash(), hash, gas_price);
|
||||||
self.transactions.insert(tx.hash(), Status::Replaced(tx, gas_price, hash));
|
self.transactions.insert(tx.hash(), Status::Replaced(tx, gas_price, hash));
|
||||||
self.clear_old();
|
self.clear_old();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_invalid(&mut self, tx: SignedTransaction) {
|
pub fn mark_invalid(&mut self, tx: SignedTransaction) {
|
||||||
|
warn!(target: "own_tx", "Transaction marked invalid (hash {:?})", tx.hash());
|
||||||
self.transactions.insert(tx.hash(), Status::Invalid(tx));
|
self.transactions.insert(tx.hash(), Status::Invalid(tx));
|
||||||
self.clear_old();
|
self.clear_old();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_dropped(&mut self, tx: SignedTransaction) {
|
pub fn mark_dropped(&mut self, tx: SignedTransaction) {
|
||||||
|
warn!(target: "own_tx", "Transaction dropped (hash {:?})", tx.hash());
|
||||||
self.transactions.insert(tx.hash(), Status::Dropped(tx));
|
self.transactions.insert(tx.hash(), Status::Dropped(tx));
|
||||||
self.clear_old();
|
self.clear_old();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_mined(&mut self, tx: SignedTransaction) {
|
pub fn mark_mined(&mut self, tx: SignedTransaction) {
|
||||||
|
info!(target: "own_tx", "Transaction mined (hash {:?})", tx.hash());
|
||||||
self.transactions.insert(tx.hash(), Status::Mined(tx));
|
self.transactions.insert(tx.hash(), Status::Mined(tx));
|
||||||
self.clear_old();
|
self.clear_old();
|
||||||
}
|
}
|
||||||
|
@ -26,15 +26,17 @@ use client::TransactionImportResult;
|
|||||||
use executive::contract_address;
|
use executive::contract_address;
|
||||||
use block::{ClosedBlock, IsBlock, Block};
|
use block::{ClosedBlock, IsBlock, Block};
|
||||||
use error::*;
|
use error::*;
|
||||||
use transaction::{Action, SignedTransaction, PendingTransaction};
|
use transaction::{Action, SignedTransaction, PendingTransaction, Condition as TransactionCondition};
|
||||||
use receipt::{Receipt, RichReceipt};
|
use receipt::{Receipt, RichReceipt};
|
||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
use engines::{Engine, Seal};
|
use engines::{Engine, Seal};
|
||||||
use miner::{MinerService, MinerStatus, TransactionQueue, PrioritizationStrategy, AccountDetails, TransactionOrigin};
|
use miner::{MinerService, MinerStatus, TransactionQueue, TransactionQueueDetailsProvider, PrioritizationStrategy,
|
||||||
|
AccountDetails, TransactionOrigin};
|
||||||
use miner::banning_queue::{BanningTransactionQueue, Threshold};
|
use miner::banning_queue::{BanningTransactionQueue, Threshold};
|
||||||
use miner::work_notify::WorkPoster;
|
use miner::work_notify::WorkPoster;
|
||||||
use miner::price_info::PriceInfo;
|
use miner::price_info::PriceInfo;
|
||||||
use miner::local_transactions::{Status as LocalTransactionStatus};
|
use miner::local_transactions::{Status as LocalTransactionStatus};
|
||||||
|
use miner::service_transaction_checker::ServiceTransactionChecker;
|
||||||
use header::BlockNumber;
|
use header::BlockNumber;
|
||||||
|
|
||||||
/// Different possible definitions for pending transaction set.
|
/// Different possible definitions for pending transaction set.
|
||||||
@ -103,8 +105,10 @@ pub struct MinerOptions {
|
|||||||
pub enable_resubmission: bool,
|
pub enable_resubmission: bool,
|
||||||
/// Global gas limit for all transaction in the queue except for local and retracted.
|
/// Global gas limit for all transaction in the queue except for local and retracted.
|
||||||
pub tx_queue_gas_limit: GasLimit,
|
pub tx_queue_gas_limit: GasLimit,
|
||||||
/// Banning settings
|
/// Banning settings.
|
||||||
pub tx_queue_banning: Banning,
|
pub tx_queue_banning: Banning,
|
||||||
|
/// Do we refuse to accept service transactions even if sender is certified.
|
||||||
|
pub refuse_service_transactions: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for MinerOptions {
|
impl Default for MinerOptions {
|
||||||
@ -123,6 +127,7 @@ impl Default for MinerOptions {
|
|||||||
work_queue_size: 20,
|
work_queue_size: 20,
|
||||||
enable_resubmission: true,
|
enable_resubmission: true,
|
||||||
tx_queue_banning: Banning::Disabled,
|
tx_queue_banning: Banning::Disabled,
|
||||||
|
refuse_service_transactions: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,7 +154,8 @@ impl GasPriceCalibrator {
|
|||||||
if Instant::now() >= self.next_calibration {
|
if Instant::now() >= self.next_calibration {
|
||||||
let usd_per_tx = self.options.usd_per_tx;
|
let usd_per_tx = self.options.usd_per_tx;
|
||||||
trace!(target: "miner", "Getting price info");
|
trace!(target: "miner", "Getting price info");
|
||||||
let price_info = PriceInfo::get(move |price: PriceInfo| {
|
|
||||||
|
PriceInfo::get(move |price: PriceInfo| {
|
||||||
trace!(target: "miner", "Price info arrived: {:?}", price);
|
trace!(target: "miner", "Price info arrived: {:?}", price);
|
||||||
let usd_per_eth = price.ethusd;
|
let usd_per_eth = price.ethusd;
|
||||||
let wei_per_usd: f32 = 1.0e18 / usd_per_eth;
|
let wei_per_usd: f32 = 1.0e18 / usd_per_eth;
|
||||||
@ -159,11 +165,7 @@ impl GasPriceCalibrator {
|
|||||||
set_price(U256::from(wei_per_gas as u64));
|
set_price(U256::from(wei_per_gas as u64));
|
||||||
});
|
});
|
||||||
|
|
||||||
if price_info.is_ok() {
|
|
||||||
self.next_calibration = Instant::now() + self.options.recalibration_period;
|
self.next_calibration = Instant::now() + self.options.recalibration_period;
|
||||||
} else {
|
|
||||||
warn!(target: "miner", "Unable to update Ether price.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,6 +227,7 @@ pub struct Miner {
|
|||||||
accounts: Option<Arc<AccountProvider>>,
|
accounts: Option<Arc<AccountProvider>>,
|
||||||
work_poster: Option<WorkPoster>,
|
work_poster: Option<WorkPoster>,
|
||||||
gas_pricer: Mutex<GasPricer>,
|
gas_pricer: Mutex<GasPricer>,
|
||||||
|
service_transaction_action: ServiceTransactionAction,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Miner {
|
impl Miner {
|
||||||
@ -248,6 +251,10 @@ impl Miner {
|
|||||||
ban_duration,
|
ban_duration,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
let service_transaction_action = match options.refuse_service_transactions {
|
||||||
|
true => ServiceTransactionAction::Refuse,
|
||||||
|
false => ServiceTransactionAction::Check(ServiceTransactionChecker::default()),
|
||||||
|
};
|
||||||
Miner {
|
Miner {
|
||||||
transaction_queue: Arc::new(Mutex::new(txq)),
|
transaction_queue: Arc::new(Mutex::new(txq)),
|
||||||
next_allowed_reseal: Mutex::new(Instant::now()),
|
next_allowed_reseal: Mutex::new(Instant::now()),
|
||||||
@ -267,6 +274,7 @@ impl Miner {
|
|||||||
engine: spec.engine.clone(),
|
engine: spec.engine.clone(),
|
||||||
work_poster: work_poster,
|
work_poster: work_poster,
|
||||||
gas_pricer: Mutex::new(gas_pricer),
|
gas_pricer: Mutex::new(gas_pricer),
|
||||||
|
service_transaction_action: service_transaction_action,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,20 +315,10 @@ impl Miner {
|
|||||||
#[cfg_attr(feature="dev", allow(match_same_arms))]
|
#[cfg_attr(feature="dev", allow(match_same_arms))]
|
||||||
/// Prepares new block for sealing including top transactions from queue.
|
/// Prepares new block for sealing including top transactions from queue.
|
||||||
fn prepare_block(&self, chain: &MiningBlockChainClient) -> (ClosedBlock, Option<H256>) {
|
fn prepare_block(&self, chain: &MiningBlockChainClient) -> (ClosedBlock, Option<H256>) {
|
||||||
{
|
|
||||||
trace!(target: "miner", "prepare_block: recalibrating...");
|
|
||||||
let txq = self.transaction_queue.clone();
|
|
||||||
self.gas_pricer.lock().recalibrate(move |price| {
|
|
||||||
trace!(target: "miner", "prepare_block: Got gas price! {}", price);
|
|
||||||
txq.lock().set_minimal_gas_price(price);
|
|
||||||
});
|
|
||||||
trace!(target: "miner", "prepare_block: done recalibration.");
|
|
||||||
}
|
|
||||||
|
|
||||||
let _timer = PerfTimer::new("prepare_block");
|
let _timer = PerfTimer::new("prepare_block");
|
||||||
let chain_info = chain.chain_info();
|
let chain_info = chain.chain_info();
|
||||||
let (transactions, mut open_block, original_work_hash) = {
|
let (transactions, mut open_block, original_work_hash) = {
|
||||||
let transactions = {self.transaction_queue.lock().top_transactions_at(chain_info.best_block_number)};
|
let transactions = {self.transaction_queue.lock().top_transactions_at(chain_info.best_block_number, chain_info.best_block_timestamp)};
|
||||||
let mut sealing_work = self.sealing_work.lock();
|
let mut sealing_work = self.sealing_work.lock();
|
||||||
let last_work_hash = sealing_work.queue.peek_last_ref().map(|pb| pb.block().fields().header.hash());
|
let last_work_hash = sealing_work.queue.peek_last_ref().map(|pb| pb.block().fields().header.hash());
|
||||||
let best_hash = chain_info.best_block_hash;
|
let best_hash = chain_info.best_block_hash;
|
||||||
@ -431,6 +429,16 @@ impl Miner {
|
|||||||
(block, original_work_hash)
|
(block, original_work_hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Asynchronously updates minimal gas price for transaction queue
|
||||||
|
pub fn recalibrate_minimal_gas_price(&self) {
|
||||||
|
debug!(target: "miner", "minimal_gas_price: recalibrating...");
|
||||||
|
let txq = self.transaction_queue.clone();
|
||||||
|
self.gas_pricer.lock().recalibrate(move |price| {
|
||||||
|
debug!(target: "miner", "minimal_gas_price: Got gas price! {}", price);
|
||||||
|
txq.lock().set_minimal_gas_price(price);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// Check is reseal is allowed and necessary.
|
/// Check is reseal is allowed and necessary.
|
||||||
fn requires_reseal(&self, best_block: BlockNumber) -> bool {
|
fn requires_reseal(&self, best_block: BlockNumber) -> bool {
|
||||||
let has_local_transactions = self.transaction_queue.lock().has_local_pending_transactions();
|
let has_local_transactions = self.transaction_queue.lock().has_local_pending_transactions();
|
||||||
@ -530,8 +538,8 @@ impl Miner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_gas_limit(&self, chain: &MiningBlockChainClient) {
|
fn update_gas_limit(&self, client: &MiningBlockChainClient) {
|
||||||
let gas_limit = chain.best_block_header().gas_limit();
|
let gas_limit = client.best_block_header().gas_limit();
|
||||||
let mut queue = self.transaction_queue.lock();
|
let mut queue = self.transaction_queue.lock();
|
||||||
queue.set_gas_limit(gas_limit);
|
queue.set_gas_limit(gas_limit);
|
||||||
if let GasLimit::Auto = self.options.tx_queue_gas_limit {
|
if let GasLimit::Auto = self.options.tx_queue_gas_limit {
|
||||||
@ -541,7 +549,7 @@ impl Miner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if we had to prepare new pending block.
|
/// Returns true if we had to prepare new pending block.
|
||||||
fn prepare_work_sealing(&self, chain: &MiningBlockChainClient) -> bool {
|
fn prepare_work_sealing(&self, client: &MiningBlockChainClient) -> bool {
|
||||||
trace!(target: "miner", "prepare_work_sealing: entering");
|
trace!(target: "miner", "prepare_work_sealing: entering");
|
||||||
let prepare_new = {
|
let prepare_new = {
|
||||||
let mut sealing_work = self.sealing_work.lock();
|
let mut sealing_work = self.sealing_work.lock();
|
||||||
@ -559,11 +567,11 @@ impl Miner {
|
|||||||
// | NOTE Code below requires transaction_queue and sealing_work locks. |
|
// | NOTE Code below requires transaction_queue and sealing_work locks. |
|
||||||
// | Make sure to release the locks before calling that method. |
|
// | Make sure to release the locks before calling that method. |
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
let (block, original_work_hash) = self.prepare_block(chain);
|
let (block, original_work_hash) = self.prepare_block(client);
|
||||||
self.prepare_work(block, original_work_hash);
|
self.prepare_work(block, original_work_hash);
|
||||||
}
|
}
|
||||||
let mut sealing_block_last_request = self.sealing_block_last_request.lock();
|
let mut sealing_block_last_request = self.sealing_block_last_request.lock();
|
||||||
let best_number = chain.chain_info().best_block_number;
|
let best_number = client.chain_info().best_block_number;
|
||||||
if *sealing_block_last_request != best_number {
|
if *sealing_block_last_request != best_number {
|
||||||
trace!(target: "miner", "prepare_work_sealing: Miner received request (was {}, now {}) - waking up.", *sealing_block_last_request, best_number);
|
trace!(target: "miner", "prepare_work_sealing: Miner received request (was {}, now {}) - waking up.", *sealing_block_last_request, best_number);
|
||||||
*sealing_block_last_request = best_number;
|
*sealing_block_last_request = best_number;
|
||||||
@ -575,39 +583,26 @@ impl Miner {
|
|||||||
|
|
||||||
fn add_transactions_to_queue(
|
fn add_transactions_to_queue(
|
||||||
&self,
|
&self,
|
||||||
chain: &MiningBlockChainClient,
|
client: &MiningBlockChainClient,
|
||||||
transactions: Vec<SignedTransaction>,
|
transactions: Vec<SignedTransaction>,
|
||||||
default_origin: TransactionOrigin,
|
default_origin: TransactionOrigin,
|
||||||
min_block: Option<BlockNumber>,
|
condition: Option<TransactionCondition>,
|
||||||
transaction_queue: &mut BanningTransactionQueue)
|
transaction_queue: &mut BanningTransactionQueue,
|
||||||
-> Vec<Result<TransactionImportResult, Error>> {
|
) -> Vec<Result<TransactionImportResult, Error>> {
|
||||||
|
|
||||||
let fetch_account = |a: &Address| AccountDetails {
|
|
||||||
nonce: chain.latest_nonce(a),
|
|
||||||
balance: chain.latest_balance(a),
|
|
||||||
};
|
|
||||||
|
|
||||||
let accounts = self.accounts.as_ref()
|
let accounts = self.accounts.as_ref()
|
||||||
.and_then(|provider| provider.accounts().ok())
|
.and_then(|provider| provider.accounts().ok())
|
||||||
.map(|accounts| accounts.into_iter().collect::<HashSet<_>>());
|
.map(|accounts| accounts.into_iter().collect::<HashSet<_>>());
|
||||||
|
|
||||||
let schedule = chain.latest_schedule();
|
let insertion_time = client.chain_info().best_block_number;
|
||||||
let gas_required = |tx: &SignedTransaction| tx.gas_required(&schedule).into();
|
let best_header = client.best_block_header().decode();
|
||||||
let best_block_header = chain.best_block_header().decode();
|
|
||||||
let insertion_time = chain.chain_info().best_block_number;
|
|
||||||
|
|
||||||
transactions.into_iter()
|
transactions.into_iter()
|
||||||
.map(|tx| {
|
.map(|tx| {
|
||||||
if chain.transaction_block(TransactionId::Hash(tx.hash())).is_some() {
|
let hash = tx.hash();
|
||||||
debug!(target: "miner", "Rejected tx {:?}: already in the blockchain", tx.hash());
|
if client.transaction_block(TransactionId::Hash(hash)).is_some() {
|
||||||
|
debug!(target: "miner", "Rejected tx {:?}: already in the blockchain", hash);
|
||||||
return Err(Error::Transaction(TransactionError::AlreadyImported));
|
return Err(Error::Transaction(TransactionError::AlreadyImported));
|
||||||
}
|
}
|
||||||
match self.engine.verify_transaction_basic(&tx, &best_block_header) {
|
|
||||||
Err(e) => {
|
|
||||||
debug!(target: "miner", "Rejected tx {:?} with invalid signature: {:?}", tx.hash(), e);
|
|
||||||
Err(e)
|
|
||||||
},
|
|
||||||
Ok(()) => {
|
|
||||||
let origin = accounts.as_ref().and_then(|accounts| {
|
let origin = accounts.as_ref().and_then(|accounts| {
|
||||||
tx.sender().ok().and_then(|sender| match accounts.contains(&sender) {
|
tx.sender().ok().and_then(|sender| match accounts.contains(&sender) {
|
||||||
true => Some(TransactionOrigin::Local),
|
true => Some(TransactionOrigin::Local),
|
||||||
@ -615,14 +610,18 @@ impl Miner {
|
|||||||
})
|
})
|
||||||
}).unwrap_or(default_origin);
|
}).unwrap_or(default_origin);
|
||||||
|
|
||||||
|
// try to install service transaction checker before appending transactions
|
||||||
|
self.service_transaction_action.update_from_chain_client(client);
|
||||||
|
|
||||||
|
self.engine.verify_transaction_basic(&tx, &best_header)?;
|
||||||
|
|
||||||
|
let details_provider = TransactionDetailsProvider::new(client, &self.service_transaction_action);
|
||||||
match origin {
|
match origin {
|
||||||
TransactionOrigin::Local | TransactionOrigin::RetractedBlock => {
|
TransactionOrigin::Local | TransactionOrigin::RetractedBlock => {
|
||||||
transaction_queue.add(tx, origin, insertion_time, min_block, &fetch_account, &gas_required)
|
transaction_queue.add(tx, origin, insertion_time, condition.clone(), &details_provider)
|
||||||
},
|
},
|
||||||
TransactionOrigin::External => {
|
TransactionOrigin::External => {
|
||||||
transaction_queue.add_with_banlist(tx, insertion_time, &fetch_account, &gas_required)
|
transaction_queue.add_with_banlist(tx, insertion_time, &details_provider)
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -673,7 +672,7 @@ impl MinerService for Miner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&self, chain: &MiningBlockChainClient, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, CallError> {
|
fn call(&self, client: &MiningBlockChainClient, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, CallError> {
|
||||||
let sealing_work = self.sealing_work.lock();
|
let sealing_work = self.sealing_work.lock();
|
||||||
match sealing_work.queue.peek_last_ref() {
|
match sealing_work.queue.peek_last_ref() {
|
||||||
Some(work) => {
|
Some(work) => {
|
||||||
@ -681,7 +680,7 @@ impl MinerService for Miner {
|
|||||||
|
|
||||||
// TODO: merge this code with client.rs's fn call somwhow.
|
// TODO: merge this code with client.rs's fn call somwhow.
|
||||||
let header = block.header();
|
let header = block.header();
|
||||||
let last_hashes = Arc::new(chain.last_hashes());
|
let last_hashes = Arc::new(client.last_hashes());
|
||||||
let env_info = EnvInfo {
|
let env_info = EnvInfo {
|
||||||
number: header.number(),
|
number: header.number(),
|
||||||
author: *header.author(),
|
author: *header.author(),
|
||||||
@ -706,16 +705,14 @@ impl MinerService for Miner {
|
|||||||
state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty);
|
state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty);
|
||||||
}
|
}
|
||||||
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
||||||
let mut ret = Executive::new(&mut state, &env_info, &*self.engine, chain.vm_factory()).transact(t, options)?;
|
let mut ret = Executive::new(&mut state, &env_info, &*self.engine, client.vm_factory()).transact(t, options)?;
|
||||||
|
|
||||||
// TODO gav move this into Executive.
|
// TODO gav move this into Executive.
|
||||||
ret.state_diff = original_state.map(|original| state.diff_from(original));
|
ret.state_diff = original_state.map(|original| state.diff_from(original));
|
||||||
|
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
},
|
},
|
||||||
None => {
|
None => client.call(t, BlockId::Latest, analytics)
|
||||||
chain.call(t, BlockId::Latest, analytics)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -872,23 +869,20 @@ impl MinerService for Miner {
|
|||||||
pending: PendingTransaction,
|
pending: PendingTransaction,
|
||||||
) -> Result<TransactionImportResult, Error> {
|
) -> Result<TransactionImportResult, Error> {
|
||||||
|
|
||||||
let hash = pending.transaction.hash();
|
|
||||||
trace!(target: "own_tx", "Importing transaction: {:?}", pending);
|
trace!(target: "own_tx", "Importing transaction: {:?}", pending);
|
||||||
|
|
||||||
let imported = {
|
let imported = {
|
||||||
// Be sure to release the lock before we call prepare_work_sealing
|
// Be sure to release the lock before we call prepare_work_sealing
|
||||||
let mut transaction_queue = self.transaction_queue.lock();
|
let mut transaction_queue = self.transaction_queue.lock();
|
||||||
let import = self.add_transactions_to_queue(
|
let import = self.add_transactions_to_queue(
|
||||||
chain, vec![pending.transaction], TransactionOrigin::Local, pending.min_block, &mut transaction_queue
|
chain, vec![pending.transaction], TransactionOrigin::Local, pending.condition, &mut transaction_queue
|
||||||
).pop().expect("one result returned per added transaction; one added => one result; qed");
|
).pop().expect("one result returned per added transaction; one added => one result; qed");
|
||||||
|
|
||||||
match import {
|
match import {
|
||||||
Ok(ref res) => {
|
Ok(_) => {
|
||||||
trace!(target: "own_tx", "Imported transaction to {:?} (hash: {:?})", res, hash);
|
|
||||||
trace!(target: "own_tx", "Status: {:?}", transaction_queue.status());
|
trace!(target: "own_tx", "Status: {:?}", transaction_queue.status());
|
||||||
},
|
},
|
||||||
Err(ref e) => {
|
Err(ref e) => {
|
||||||
trace!(target: "own_tx", "Failed to import transaction {:?} (hash: {:?})", e, hash);
|
|
||||||
trace!(target: "own_tx", "Status: {:?}", transaction_queue.status());
|
trace!(target: "own_tx", "Status: {:?}", transaction_queue.status());
|
||||||
warn!(target: "own_tx", "Error importing transaction: {:?}", e);
|
warn!(target: "own_tx", "Error importing transaction: {:?}", e);
|
||||||
},
|
},
|
||||||
@ -916,7 +910,7 @@ impl MinerService for Miner {
|
|||||||
|
|
||||||
fn pending_transactions(&self) -> Vec<PendingTransaction> {
|
fn pending_transactions(&self) -> Vec<PendingTransaction> {
|
||||||
let queue = self.transaction_queue.lock();
|
let queue = self.transaction_queue.lock();
|
||||||
queue.pending_transactions(BlockNumber::max_value())
|
queue.pending_transactions(BlockNumber::max_value(), u64::max_value())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn local_transactions(&self) -> BTreeMap<H256, LocalTransactionStatus> {
|
fn local_transactions(&self) -> BTreeMap<H256, LocalTransactionStatus> {
|
||||||
@ -931,14 +925,14 @@ impl MinerService for Miner {
|
|||||||
self.transaction_queue.lock().future_transactions()
|
self.transaction_queue.lock().future_transactions()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ready_transactions(&self, best_block: BlockNumber) -> Vec<PendingTransaction> {
|
fn ready_transactions(&self, best_block: BlockNumber, best_block_timestamp: u64) -> Vec<PendingTransaction> {
|
||||||
let queue = self.transaction_queue.lock();
|
let queue = self.transaction_queue.lock();
|
||||||
match self.options.pending_set {
|
match self.options.pending_set {
|
||||||
PendingSet::AlwaysQueue => queue.pending_transactions(best_block),
|
PendingSet::AlwaysQueue => queue.pending_transactions(best_block, best_block_timestamp),
|
||||||
PendingSet::SealingOrElseQueue => {
|
PendingSet::SealingOrElseQueue => {
|
||||||
self.from_pending_block(
|
self.from_pending_block(
|
||||||
best_block,
|
best_block,
|
||||||
|| queue.pending_transactions(best_block),
|
|| queue.pending_transactions(best_block, best_block_timestamp),
|
||||||
|sealing| sealing.transactions().iter().map(|t| t.clone().into()).collect()
|
|sealing| sealing.transactions().iter().map(|t| t.clone().into()).collect()
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -1126,6 +1120,9 @@ impl MinerService for Miner {
|
|||||||
// First update gas limit in transaction queue
|
// First update gas limit in transaction queue
|
||||||
self.update_gas_limit(chain);
|
self.update_gas_limit(chain);
|
||||||
|
|
||||||
|
// Update minimal gas price
|
||||||
|
self.recalibrate_minimal_gas_price();
|
||||||
|
|
||||||
// Then import all transactions...
|
// Then import all transactions...
|
||||||
{
|
{
|
||||||
retracted.par_iter()
|
retracted.par_iter()
|
||||||
@ -1167,6 +1164,60 @@ impl MinerService for Miner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Action when service transaction is received
|
||||||
|
enum ServiceTransactionAction {
|
||||||
|
/// Refuse service transaction immediately
|
||||||
|
Refuse,
|
||||||
|
/// Accept if sender is certified to send service transactions
|
||||||
|
Check(ServiceTransactionChecker),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServiceTransactionAction {
|
||||||
|
pub fn update_from_chain_client(&self, client: &MiningBlockChainClient) {
|
||||||
|
if let ServiceTransactionAction::Check(ref checker) = *self {
|
||||||
|
checker.update_from_chain_client(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check(&self, client: &MiningBlockChainClient, tx: &SignedTransaction) -> Result<bool, String> {
|
||||||
|
match *self {
|
||||||
|
ServiceTransactionAction::Refuse => Err("configured to refuse service transactions".to_owned()),
|
||||||
|
ServiceTransactionAction::Check(ref checker) => checker.check(client, tx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TransactionDetailsProvider<'a> {
|
||||||
|
client: &'a MiningBlockChainClient,
|
||||||
|
service_transaction_action: &'a ServiceTransactionAction,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TransactionDetailsProvider<'a> {
|
||||||
|
pub fn new(client: &'a MiningBlockChainClient, service_transaction_action: &'a ServiceTransactionAction) -> Self {
|
||||||
|
TransactionDetailsProvider {
|
||||||
|
client: client,
|
||||||
|
service_transaction_action: service_transaction_action,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TransactionQueueDetailsProvider for TransactionDetailsProvider<'a> {
|
||||||
|
fn fetch_account(&self, address: &Address) -> AccountDetails {
|
||||||
|
AccountDetails {
|
||||||
|
nonce: self.client.latest_nonce(address),
|
||||||
|
balance: self.client.latest_balance(address),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn estimate_gas_required(&self, tx: &SignedTransaction) -> U256 {
|
||||||
|
tx.gas_required(&self.client.latest_schedule()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_service_transaction_acceptable(&self, tx: &SignedTransaction) -> Result<bool, String> {
|
||||||
|
self.service_transaction_action.check(self.client, tx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
@ -1231,6 +1282,7 @@ mod tests {
|
|||||||
work_queue_size: 5,
|
work_queue_size: 5,
|
||||||
enable_resubmission: true,
|
enable_resubmission: true,
|
||||||
tx_queue_banning: Banning::Disabled,
|
tx_queue_banning: Banning::Disabled,
|
||||||
|
refuse_service_transactions: false,
|
||||||
},
|
},
|
||||||
GasPricer::new_fixed(0u64.into()),
|
GasPricer::new_fixed(0u64.into()),
|
||||||
&Spec::new_test(),
|
&Spec::new_test(),
|
||||||
@ -1263,7 +1315,7 @@ mod tests {
|
|||||||
// then
|
// then
|
||||||
assert_eq!(res.unwrap(), TransactionImportResult::Current);
|
assert_eq!(res.unwrap(), TransactionImportResult::Current);
|
||||||
assert_eq!(miner.pending_transactions().len(), 1);
|
assert_eq!(miner.pending_transactions().len(), 1);
|
||||||
assert_eq!(miner.ready_transactions(best_block).len(), 1);
|
assert_eq!(miner.ready_transactions(best_block, 0).len(), 1);
|
||||||
assert_eq!(miner.pending_transactions_hashes(best_block).len(), 1);
|
assert_eq!(miner.pending_transactions_hashes(best_block).len(), 1);
|
||||||
assert_eq!(miner.pending_receipts(best_block).len(), 1);
|
assert_eq!(miner.pending_receipts(best_block).len(), 1);
|
||||||
// This method will let us know if pending block was created (before calling that method)
|
// This method will let us know if pending block was created (before calling that method)
|
||||||
@ -1283,7 +1335,7 @@ mod tests {
|
|||||||
// then
|
// then
|
||||||
assert_eq!(res.unwrap(), TransactionImportResult::Current);
|
assert_eq!(res.unwrap(), TransactionImportResult::Current);
|
||||||
assert_eq!(miner.pending_transactions().len(), 1);
|
assert_eq!(miner.pending_transactions().len(), 1);
|
||||||
assert_eq!(miner.ready_transactions(best_block).len(), 0);
|
assert_eq!(miner.ready_transactions(best_block, 0).len(), 0);
|
||||||
assert_eq!(miner.pending_transactions_hashes(best_block).len(), 0);
|
assert_eq!(miner.pending_transactions_hashes(best_block).len(), 0);
|
||||||
assert_eq!(miner.pending_receipts(best_block).len(), 0);
|
assert_eq!(miner.pending_receipts(best_block).len(), 0);
|
||||||
}
|
}
|
||||||
@ -1302,7 +1354,7 @@ mod tests {
|
|||||||
assert_eq!(res.unwrap(), TransactionImportResult::Current);
|
assert_eq!(res.unwrap(), TransactionImportResult::Current);
|
||||||
assert_eq!(miner.pending_transactions().len(), 1);
|
assert_eq!(miner.pending_transactions().len(), 1);
|
||||||
assert_eq!(miner.pending_transactions_hashes(best_block).len(), 0);
|
assert_eq!(miner.pending_transactions_hashes(best_block).len(), 0);
|
||||||
assert_eq!(miner.ready_transactions(best_block).len(), 0);
|
assert_eq!(miner.ready_transactions(best_block, 0).len(), 0);
|
||||||
assert_eq!(miner.pending_receipts(best_block).len(), 0);
|
assert_eq!(miner.pending_receipts(best_block).len(), 0);
|
||||||
// This method will let us know if pending block was created (before calling that method)
|
// This method will let us know if pending block was created (before calling that method)
|
||||||
assert!(miner.prepare_work_sealing(&client));
|
assert!(miner.prepare_work_sealing(&client));
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
//! use ethcore::miner::{Miner, MinerService};
|
//! use ethcore::miner::{Miner, MinerService};
|
||||||
//!
|
//!
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
//! let miner: Miner = Miner::with_spec(ðereum::new_frontier());
|
//! let miner: Miner = Miner::with_spec(ðereum::new_foundation());
|
||||||
//! // get status
|
//! // get status
|
||||||
//! assert_eq!(miner.status().transactions_in_pending_queue, 0);
|
//! assert_eq!(miner.status().transactions_in_pending_queue, 0);
|
||||||
//!
|
//!
|
||||||
@ -46,12 +46,14 @@ mod external;
|
|||||||
mod local_transactions;
|
mod local_transactions;
|
||||||
mod miner;
|
mod miner;
|
||||||
mod price_info;
|
mod price_info;
|
||||||
|
mod service_transaction_checker;
|
||||||
mod transaction_queue;
|
mod transaction_queue;
|
||||||
mod work_notify;
|
mod work_notify;
|
||||||
|
|
||||||
pub use self::external::{ExternalMiner, ExternalMinerService};
|
pub use self::external::{ExternalMiner, ExternalMinerService};
|
||||||
pub use self::miner::{Miner, MinerOptions, Banning, PendingSet, GasPricer, GasPriceCalibratorOptions, GasLimit};
|
pub use self::miner::{Miner, MinerOptions, Banning, PendingSet, GasPricer, GasPriceCalibratorOptions, GasLimit};
|
||||||
pub use self::transaction_queue::{TransactionQueue, PrioritizationStrategy, AccountDetails, TransactionOrigin};
|
pub use self::transaction_queue::{TransactionQueue, TransactionDetailsProvider as TransactionQueueDetailsProvider,
|
||||||
|
PrioritizationStrategy, AccountDetails, TransactionOrigin};
|
||||||
pub use self::local_transactions::{Status as LocalTransactionStatus};
|
pub use self::local_transactions::{Status as LocalTransactionStatus};
|
||||||
pub use client::TransactionImportResult;
|
pub use client::TransactionImportResult;
|
||||||
|
|
||||||
@ -148,7 +150,7 @@ pub trait MinerService : Send + Sync {
|
|||||||
fn pending_transactions(&self) -> Vec<PendingTransaction>;
|
fn pending_transactions(&self) -> Vec<PendingTransaction>;
|
||||||
|
|
||||||
/// Get a list of all transactions that can go into the given block.
|
/// Get a list of all transactions that can go into the given block.
|
||||||
fn ready_transactions(&self, best_block: BlockNumber) -> Vec<PendingTransaction>;
|
fn ready_transactions(&self, best_block: BlockNumber, best_block_timestamp: u64) -> Vec<PendingTransaction>;
|
||||||
|
|
||||||
/// Get a list of all future transactions.
|
/// Get a list of all future transactions.
|
||||||
fn future_transactions(&self) -> Vec<PendingTransaction>;
|
fn future_transactions(&self) -> Vec<PendingTransaction>;
|
||||||
|
@ -21,7 +21,7 @@ use std::time::Duration;
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use hyper::client::{Handler, Request, Response, Client};
|
use hyper::client::{Handler, Request, Response, Client};
|
||||||
use hyper::{Next, Encoder, Decoder};
|
use hyper::{Url, Next, Encoder, Decoder};
|
||||||
use hyper::net::HttpStream;
|
use hyper::net::HttpStream;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -29,12 +29,12 @@ pub struct PriceInfo {
|
|||||||
pub ethusd: f32,
|
pub ethusd: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SetPriceHandler<F: Fn(PriceInfo) + Sync + Send + 'static> {
|
pub struct SetPriceHandler<F> {
|
||||||
set_price: F,
|
set_price: F,
|
||||||
channel: mpsc::Sender<()>,
|
channel: mpsc::Sender<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Fn(PriceInfo) + Sync + Send + 'static> Drop for SetPriceHandler<F> {
|
impl<F> Drop for SetPriceHandler<F> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let _ = self.channel.send(());
|
let _ = self.channel.send(());
|
||||||
}
|
}
|
||||||
@ -47,42 +47,66 @@ impl<F: Fn(PriceInfo) + Sync + Send + 'static> Handler<HttpStream> for SetPriceH
|
|||||||
|
|
||||||
fn on_response_readable(&mut self, r: &mut Decoder<HttpStream>) -> Next {
|
fn on_response_readable(&mut self, r: &mut Decoder<HttpStream>) -> Next {
|
||||||
let mut body = String::new();
|
let mut body = String::new();
|
||||||
let _ = r.read_to_string(&mut body).ok()
|
let info = r.read_to_string(&mut body)
|
||||||
.and_then(|_| Json::from_str(&body).ok())
|
.map_err(|e| format!("Unable to read response: {:?}", e))
|
||||||
.and_then(|json| json.find_path(&["result", "ethusd"])
|
.and_then(|_| self.process_response(&body));
|
||||||
.and_then(|obj| match *obj {
|
|
||||||
Json::String(ref s) => Some((self.set_price)(PriceInfo {
|
if let Err(e) = info {
|
||||||
ethusd: FromStr::from_str(s)
|
warn!("Failed to auto-update latest ETH price: {:?}", e);
|
||||||
.expect("Etherscan API will always return properly formatted price; qed")
|
}
|
||||||
})),
|
|
||||||
_ => None,
|
|
||||||
}));
|
|
||||||
Next::end()
|
Next::end()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PriceInfo {
|
impl<F: Fn(PriceInfo) + Sync + Send + 'static> SetPriceHandler<F> {
|
||||||
pub fn get<F: Fn(PriceInfo) + Sync + Send + 'static>(set_price: F) -> Result<(), ()> {
|
fn process_response(&self, body: &str) -> Result<(), String> {
|
||||||
// TODO: Handle each error type properly
|
let json = Json::from_str(body).map_err(|e| format!("Invalid JSON returned: {:?}", e))?;
|
||||||
let client = Client::new().map_err(|_| ())?;
|
let obj = json.find_path(&["result", "ethusd"]).ok_or("USD price not found".to_owned())?;
|
||||||
thread::spawn(move || {
|
let ethusd = match *obj {
|
||||||
let (tx, rx) = mpsc::channel();
|
Json::String(ref s) => FromStr::from_str(s).ok(),
|
||||||
let url = FromStr::from_str("http://api.etherscan.io/api?module=stats&action=ethprice")
|
_ => None,
|
||||||
.expect("string known to be a valid URL; qed");
|
}.ok_or("Unexpected price format.".to_owned())?;
|
||||||
let _ = client.request(
|
|
||||||
url,
|
(self.set_price)(PriceInfo {
|
||||||
SetPriceHandler {
|
ethusd: ethusd,
|
||||||
set_price: set_price,
|
|
||||||
channel: tx,
|
|
||||||
}).ok().and_then(|_| rx.recv().ok());
|
|
||||||
client.close();
|
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
impl PriceInfo {
|
||||||
|
pub fn get<F: Fn(PriceInfo) + Sync + Send + 'static>(set_price: F) {
|
||||||
|
thread::spawn(move || {
|
||||||
|
let url = FromStr::from_str("http://api.etherscan.io/api?module=stats&action=ethprice")
|
||||||
|
.expect("string known to be a valid URL; qed");
|
||||||
|
|
||||||
|
if let Err(e) = Self::request(url, set_price) {
|
||||||
|
warn!("Failed to auto-update latest ETH price: {:?}", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request<F: Fn(PriceInfo) + Send + Sync + 'static>(url: Url, set_price: F) -> Result<(), String> {
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
let client = Client::new().map_err(|e| format!("Unable to start client: {:?}", e))?;
|
||||||
|
|
||||||
|
client.request(
|
||||||
|
url,
|
||||||
|
SetPriceHandler {
|
||||||
|
set_price: set_price,
|
||||||
|
channel: tx,
|
||||||
|
},
|
||||||
|
).map_err(|_| "Request failed.".to_owned())?;
|
||||||
|
|
||||||
|
// Wait for exit
|
||||||
|
let _ = rx.recv().map_err(|e| format!("Request interrupted: {:?}", e))?;
|
||||||
|
client.close();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test] #[ignore]
|
||||||
fn should_get_price_info() {
|
fn should_get_price_info() {
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@ -93,7 +117,7 @@ fn should_get_price_info() {
|
|||||||
let done = Arc::new((Mutex::new(PriceInfo { ethusd: 0f32 }), Condvar::new()));
|
let done = Arc::new((Mutex::new(PriceInfo { ethusd: 0f32 }), Condvar::new()));
|
||||||
let rdone = done.clone();
|
let rdone = done.clone();
|
||||||
|
|
||||||
PriceInfo::get(move |price| { let mut p = rdone.0.lock(); *p = price; rdone.1.notify_one(); }).unwrap();
|
PriceInfo::get(move |price| { let mut p = rdone.0.lock(); *p = price; rdone.1.notify_one(); });
|
||||||
let mut p = done.0.lock();
|
let mut p = done.0.lock();
|
||||||
let t = done.1.wait_for(&mut p, Duration::from_millis(10000));
|
let t = done.1.wait_for(&mut p, Duration::from_millis(10000));
|
||||||
assert!(!t.timed_out());
|
assert!(!t.timed_out());
|
||||||
|
212
ethcore/src/miner/service_transaction_checker.rs
Normal file
212
ethcore/src/miner/service_transaction_checker.rs
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
// Copyright 2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use client::MiningBlockChainClient;
|
||||||
|
use transaction::SignedTransaction;
|
||||||
|
use util::{U256, Uint, Mutex};
|
||||||
|
|
||||||
|
const SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME: &'static str = "service_transaction_checker";
|
||||||
|
|
||||||
|
/// Service transactions checker.
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct ServiceTransactionChecker {
|
||||||
|
contract: Mutex<Option<provider::Contract>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServiceTransactionChecker {
|
||||||
|
/// Try to create instance, reading contract address from given chain client.
|
||||||
|
pub fn update_from_chain_client(&self, client: &MiningBlockChainClient) {
|
||||||
|
let mut contract = self.contract.lock();
|
||||||
|
if contract.is_none() {
|
||||||
|
*contract = client.registry_address(SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME.to_owned())
|
||||||
|
.and_then(|contract_addr| {
|
||||||
|
trace!(target: "txqueue", "Configuring for service transaction checker contract from {}", contract_addr);
|
||||||
|
|
||||||
|
Some(provider::Contract::new(contract_addr))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if service transaction can be appended to the transaction queue.
|
||||||
|
pub fn check(&self, client: &MiningBlockChainClient, tx: &SignedTransaction) -> Result<bool, String> {
|
||||||
|
debug_assert_eq!(tx.gas_price, U256::zero());
|
||||||
|
|
||||||
|
if let Some(ref contract) = *self.contract.lock() {
|
||||||
|
let do_call = |a, d| client.call_contract(a, d);
|
||||||
|
contract.certified(&do_call, &tx.sender().unwrap())
|
||||||
|
} else {
|
||||||
|
Err("contract is not configured".to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod provider {
|
||||||
|
// Autogenerated from JSON contract definition using Rust contract convertor.
|
||||||
|
// Command line: --jsonabi=SimpleCertifier.abi --explicit-do-call
|
||||||
|
#![allow(unused_imports)]
|
||||||
|
use std::string::String;
|
||||||
|
use std::result::Result;
|
||||||
|
use std::fmt;
|
||||||
|
use {util, ethabi};
|
||||||
|
use util::{FixedHash, Uint};
|
||||||
|
|
||||||
|
pub struct Contract {
|
||||||
|
contract: ethabi::Contract,
|
||||||
|
address: util::Address,
|
||||||
|
|
||||||
|
}
|
||||||
|
impl Contract {
|
||||||
|
pub fn new(address: util::Address) -> Self
|
||||||
|
{
|
||||||
|
Contract {
|
||||||
|
contract: ethabi::Contract::new(ethabi::Interface::load(b"[{\"constant\":false,\"inputs\":[{\"name\":\"_new\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_who\",\"type\":\"address\"}],\"name\":\"certify\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_who\",\"type\":\"address\"},{\"name\":\"_field\",\"type\":\"string\"}],\"name\":\"getAddress\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_who\",\"type\":\"address\"}],\"name\":\"revoke\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"delegate\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_who\",\"type\":\"address\"},{\"name\":\"_field\",\"type\":\"string\"}],\"name\":\"getUint\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_new\",\"type\":\"address\"}],\"name\":\"setDelegate\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_who\",\"type\":\"address\"}],\"name\":\"certified\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_who\",\"type\":\"address\"},{\"name\":\"_field\",\"type\":\"string\"}],\"name\":\"get\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"type\":\"function\"}]").expect("JSON is autogenerated; qed")),
|
||||||
|
address: address,
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn as_string<T: fmt::Debug>(e: T) -> String { format!("{:?}", e) }
|
||||||
|
|
||||||
|
/// Auto-generated from: `{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"}`
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn set_owner<F>(&self, do_call: &F, _new: &util::Address) -> Result<(), String>
|
||||||
|
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send {
|
||||||
|
let call = self.contract.function("setOwner".into()).map_err(Self::as_string)?;
|
||||||
|
let data = call.encode_call(
|
||||||
|
vec![ethabi::Token::Address(_new.clone().0)]
|
||||||
|
).map_err(Self::as_string)?;
|
||||||
|
call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Auto-generated from: `{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"certify","outputs":[],"payable":false,"type":"function"}`
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn certify<F>(&self, do_call: &F, _who: &util::Address) -> Result<(), String>
|
||||||
|
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send {
|
||||||
|
let call = self.contract.function("certify".into()).map_err(Self::as_string)?;
|
||||||
|
let data = call.encode_call(
|
||||||
|
vec![ethabi::Token::Address(_who.clone().0)]
|
||||||
|
).map_err(Self::as_string)?;
|
||||||
|
call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Auto-generated from: `{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"}`
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn get_address<F>(&self, do_call: &F, _who: &util::Address, _field: &str) -> Result<util::Address, String>
|
||||||
|
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send {
|
||||||
|
let call = self.contract.function("getAddress".into()).map_err(Self::as_string)?;
|
||||||
|
let data = call.encode_call(
|
||||||
|
vec![ethabi::Token::Address(_who.clone().0), ethabi::Token::String(_field.to_owned())]
|
||||||
|
).map_err(Self::as_string)?;
|
||||||
|
let output = call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
|
||||||
|
let mut result = output.into_iter().rev().collect::<Vec<_>>();
|
||||||
|
Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_address().ok_or("Invalid type returned")?; util::Address::from(r) }))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Auto-generated from: `{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"revoke","outputs":[],"payable":false,"type":"function"}`
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn revoke<F>(&self, do_call: &F, _who: &util::Address) -> Result<(), String>
|
||||||
|
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send {
|
||||||
|
let call = self.contract.function("revoke".into()).map_err(Self::as_string)?;
|
||||||
|
let data = call.encode_call(
|
||||||
|
vec![ethabi::Token::Address(_who.clone().0)]
|
||||||
|
).map_err(Self::as_string)?;
|
||||||
|
call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Auto-generated from: `{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"}`
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn owner<F>(&self, do_call: &F) -> Result<util::Address, String>
|
||||||
|
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send {
|
||||||
|
let call = self.contract.function("owner".into()).map_err(Self::as_string)?;
|
||||||
|
let data = call.encode_call(
|
||||||
|
vec![]
|
||||||
|
).map_err(Self::as_string)?;
|
||||||
|
let output = call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
|
||||||
|
let mut result = output.into_iter().rev().collect::<Vec<_>>();
|
||||||
|
Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_address().ok_or("Invalid type returned")?; util::Address::from(r) }))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Auto-generated from: `{"constant":true,"inputs":[],"name":"delegate","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"}`
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn delegate<F>(&self, do_call: &F) -> Result<util::Address, String>
|
||||||
|
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send {
|
||||||
|
let call = self.contract.function("delegate".into()).map_err(Self::as_string)?;
|
||||||
|
let data = call.encode_call(
|
||||||
|
vec![]
|
||||||
|
).map_err(Self::as_string)?;
|
||||||
|
let output = call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
|
||||||
|
let mut result = output.into_iter().rev().collect::<Vec<_>>();
|
||||||
|
Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_address().ok_or("Invalid type returned")?; util::Address::from(r) }))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Auto-generated from: `{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"}`
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn get_uint<F>(&self, do_call: &F, _who: &util::Address, _field: &str) -> Result<util::U256, String>
|
||||||
|
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send {
|
||||||
|
let call = self.contract.function("getUint".into()).map_err(Self::as_string)?;
|
||||||
|
let data = call.encode_call(
|
||||||
|
vec![ethabi::Token::Address(_who.clone().0), ethabi::Token::String(_field.to_owned())]
|
||||||
|
).map_err(Self::as_string)?;
|
||||||
|
let output = call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
|
||||||
|
let mut result = output.into_iter().rev().collect::<Vec<_>>();
|
||||||
|
Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_uint().ok_or("Invalid type returned")?; util::U256::from(r.as_ref()) }))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Auto-generated from: `{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setDelegate","outputs":[],"payable":false,"type":"function"}`
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn set_delegate<F>(&self, do_call: &F, _new: &util::Address) -> Result<(), String>
|
||||||
|
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send {
|
||||||
|
let call = self.contract.function("setDelegate".into()).map_err(Self::as_string)?;
|
||||||
|
let data = call.encode_call(
|
||||||
|
vec![ethabi::Token::Address(_new.clone().0)]
|
||||||
|
).map_err(Self::as_string)?;
|
||||||
|
call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Auto-generated from: `{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"certified","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"}`
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn certified<F>(&self, do_call: &F, _who: &util::Address) -> Result<bool, String>
|
||||||
|
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send {
|
||||||
|
let call = self.contract.function("certified".into()).map_err(Self::as_string)?;
|
||||||
|
let data = call.encode_call(
|
||||||
|
vec![ethabi::Token::Address(_who.clone().0)]
|
||||||
|
).map_err(Self::as_string)?;
|
||||||
|
let output = call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
|
||||||
|
let mut result = output.into_iter().rev().collect::<Vec<_>>();
|
||||||
|
Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_bool().ok_or("Invalid type returned")?; r }))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Auto-generated from: `{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"}`
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn get<F>(&self, do_call: &F, _who: &util::Address, _field: &str) -> Result<util::H256, String>
|
||||||
|
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send {
|
||||||
|
let call = self.contract.function("get".into()).map_err(Self::as_string)?;
|
||||||
|
let data = call.encode_call(
|
||||||
|
vec![ethabi::Token::Address(_who.clone().0), ethabi::Token::String(_field.to_owned())]
|
||||||
|
).map_err(Self::as_string)?;
|
||||||
|
let output = call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
|
||||||
|
let mut result = output.into_iter().rev().collect::<Vec<_>>();
|
||||||
|
Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_fixed_bytes().ok_or("Invalid type returned")?; util::H256::from_slice(r.as_ref()) }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -157,7 +157,7 @@ impl Spec {
|
|||||||
fn engine(engine_spec: ethjson::spec::Engine, params: CommonParams, builtins: BTreeMap<Address, Builtin>) -> Arc<Engine> {
|
fn engine(engine_spec: ethjson::spec::Engine, params: CommonParams, builtins: BTreeMap<Address, Builtin>) -> Arc<Engine> {
|
||||||
match engine_spec {
|
match engine_spec {
|
||||||
ethjson::spec::Engine::Null => Arc::new(NullEngine::new(params, builtins)),
|
ethjson::spec::Engine::Null => Arc::new(NullEngine::new(params, builtins)),
|
||||||
ethjson::spec::Engine::InstantSeal => Arc::new(InstantSeal::new(params, builtins)),
|
ethjson::spec::Engine::InstantSeal(instant) => Arc::new(InstantSeal::new(params, instant.params.registrar.map_or_else(Address::new, Into::into), builtins)),
|
||||||
ethjson::spec::Engine::Ethash(ethash) => Arc::new(ethereum::Ethash::new(params, From::from(ethash.params), builtins)),
|
ethjson::spec::Engine::Ethash(ethash) => Arc::new(ethereum::Ethash::new(params, From::from(ethash.params), builtins)),
|
||||||
ethjson::spec::Engine::BasicAuthority(basic_authority) => Arc::new(BasicAuthority::new(params, From::from(basic_authority.params), builtins)),
|
ethjson::spec::Engine::BasicAuthority(basic_authority) => Arc::new(BasicAuthority::new(params, From::from(basic_authority.params), builtins)),
|
||||||
ethjson::spec::Engine::AuthorityRound(authority_round) => AuthorityRound::new(params, From::from(authority_round.params), builtins).expect("Failed to start AuthorityRound consensus engine."),
|
ethjson::spec::Engine::AuthorityRound(authority_round) => AuthorityRound::new(params, From::from(authority_round.params), builtins).expect("Failed to start AuthorityRound consensus engine."),
|
||||||
|
@ -844,6 +844,7 @@ mod tests {
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use rustc_serialize::hex::FromHex;
|
use rustc_serialize::hex::FromHex;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use ethkey::Secret;
|
||||||
use util::{U256, H256, FixedHash, Address, Hashable};
|
use util::{U256, H256, FixedHash, Address, Hashable};
|
||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
use devtools::*;
|
use devtools::*;
|
||||||
@ -854,6 +855,10 @@ mod tests {
|
|||||||
use trace::{FlatTrace, TraceError, trace};
|
use trace::{FlatTrace, TraceError, trace};
|
||||||
use types::executed::CallType;
|
use types::executed::CallType;
|
||||||
|
|
||||||
|
fn secret() -> Secret {
|
||||||
|
Secret::from_slice(&"".sha3()).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_apply_create_transaction() {
|
fn should_apply_create_transaction() {
|
||||||
init_log();
|
init_log();
|
||||||
@ -872,7 +877,7 @@ mod tests {
|
|||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555").unwrap(),
|
data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555").unwrap(),
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
||||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||||
@ -932,7 +937,7 @@ mod tests {
|
|||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: FromHex::from_hex("5b600056").unwrap(),
|
data: FromHex::from_hex("5b600056").unwrap(),
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
||||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||||
@ -969,7 +974,7 @@ mod tests {
|
|||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("6000").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("6000").unwrap());
|
||||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
||||||
@ -1012,7 +1017,7 @@ mod tests {
|
|||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
||||||
let result = state.apply(&info, &engine, &t, true).unwrap();
|
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||||
@ -1054,7 +1059,7 @@ mod tests {
|
|||||||
action: Action::Call(0x1.into()),
|
action: Action::Call(0x1.into()),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
let result = state.apply(&info, engine, &t, true).unwrap();
|
let result = state.apply(&info, engine, &t, true).unwrap();
|
||||||
|
|
||||||
@ -1096,7 +1101,7 @@ mod tests {
|
|||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060006001610be0f1").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060006001610be0f1").unwrap());
|
||||||
let result = state.apply(&info, engine, &t, true).unwrap();
|
let result = state.apply(&info, engine, &t, true).unwrap();
|
||||||
@ -1139,7 +1144,7 @@ mod tests {
|
|||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b611000f2").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b611000f2").unwrap());
|
||||||
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
|
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
|
||||||
@ -1201,7 +1206,7 @@ mod tests {
|
|||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("6000600060006000600b618000f4").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("6000600060006000600b618000f4").unwrap());
|
||||||
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
|
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
|
||||||
@ -1260,7 +1265,7 @@ mod tests {
|
|||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("5b600056").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("5b600056").unwrap());
|
||||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
||||||
@ -1300,7 +1305,7 @@ mod tests {
|
|||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
|
||||||
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
|
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
|
||||||
@ -1360,7 +1365,7 @@ mod tests {
|
|||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006045600b6000f1").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006045600b6000f1").unwrap());
|
||||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
||||||
@ -1415,7 +1420,7 @@ mod tests {
|
|||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()); // not enough funds.
|
state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()); // not enough funds.
|
||||||
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
|
||||||
@ -1458,7 +1463,7 @@ mod tests {
|
|||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: vec![],//600480600b6000396000f35b600056
|
data: vec![],//600480600b6000396000f35b600056
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
|
||||||
state.init_code(&0xb.into(), FromHex::from_hex("5b600056").unwrap());
|
state.init_code(&0xb.into(), FromHex::from_hex("5b600056").unwrap());
|
||||||
@ -1514,7 +1519,7 @@ mod tests {
|
|||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
|
||||||
state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap());
|
state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap());
|
||||||
@ -1589,7 +1594,7 @@ mod tests {
|
|||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: vec![],//600480600b6000396000f35b600056
|
data: vec![],//600480600b6000396000f35b600056
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
|
||||||
state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap());
|
state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap());
|
||||||
@ -1662,7 +1667,7 @@ mod tests {
|
|||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}.sign(&"".sha3(), None);
|
}.sign(&secret(), None);
|
||||||
|
|
||||||
state.init_code(&0xa.into(), FromHex::from_hex("73000000000000000000000000000000000000000bff").unwrap());
|
state.init_code(&0xa.into(), FromHex::from_hex("73000000000000000000000000000000000000000bff").unwrap());
|
||||||
state.add_balance(&0xa.into(), &50.into(), CleanupMode::NoEmpty);
|
state.add_balance(&0xa.into(), &50.into(), CleanupMode::NoEmpty);
|
||||||
|
@ -28,8 +28,8 @@ use rlp::View;
|
|||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
use views::BlockView;
|
use views::BlockView;
|
||||||
use util::stats::Histogram;
|
use util::stats::Histogram;
|
||||||
use ethkey::KeyPair;
|
use ethkey::{KeyPair, Secret};
|
||||||
use transaction::{PendingTransaction, Transaction, Action};
|
use transaction::{PendingTransaction, Transaction, Action, Condition};
|
||||||
use miner::MinerService;
|
use miner::MinerService;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -233,6 +233,13 @@ fn empty_gas_price_histogram() {
|
|||||||
assert!(client.gas_price_histogram(20, 5).is_none());
|
assert!(client.gas_price_histogram(20, 5).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn corpus_is_sorted() {
|
||||||
|
let client_result = generate_dummy_client_with_data(2, 1, slice_into![U256::from_str("11426908979").unwrap(), U256::from_str("50426908979").unwrap()]);
|
||||||
|
let client = client_result.reference();
|
||||||
|
let corpus = client.gas_price_corpus(20);
|
||||||
|
assert!(corpus[0] < corpus[1]);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_handle_long_fork() {
|
fn can_handle_long_fork() {
|
||||||
@ -290,7 +297,7 @@ fn change_history_size() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn does_not_propagate_delayed_transactions() {
|
fn does_not_propagate_delayed_transactions() {
|
||||||
let key = KeyPair::from_secret("test".sha3()).unwrap();
|
let key = KeyPair::from_secret(Secret::from_slice(&"test".sha3()).unwrap()).unwrap();
|
||||||
let secret = key.secret();
|
let secret = key.secret();
|
||||||
let tx0 = PendingTransaction::new(Transaction {
|
let tx0 = PendingTransaction::new(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
@ -299,7 +306,7 @@ fn does_not_propagate_delayed_transactions() {
|
|||||||
action: Action::Call(Address::default()),
|
action: Action::Call(Address::default()),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
data: Vec::new(),
|
data: Vec::new(),
|
||||||
}.sign(secret, None), Some(2));
|
}.sign(secret, None), Some(Condition::Number(2)));
|
||||||
let tx1 = PendingTransaction::new(Transaction {
|
let tx1 = PendingTransaction::new(Transaction {
|
||||||
nonce: 1.into(),
|
nonce: 1.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
|
@ -163,7 +163,7 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
|
|||||||
let mut last_hashes = vec![];
|
let mut last_hashes = vec![];
|
||||||
let mut last_header = genesis_header.clone();
|
let mut last_header = genesis_header.clone();
|
||||||
|
|
||||||
let kp = KeyPair::from_secret("".sha3()).unwrap();
|
let kp = KeyPair::from_secret_slice(&"".sha3()).unwrap();
|
||||||
let author = kp.address();
|
let author = kp.address();
|
||||||
|
|
||||||
let mut n = 0;
|
let mut n = 0;
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
//! Trace database.
|
//! Trace database.
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::collections::HashMap;
|
use std::collections::{HashMap, VecDeque};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use bloomchain::{Number, Config as BloomConfig};
|
use bloomchain::{Number, Config as BloomConfig};
|
||||||
use bloomchain::group::{BloomGroupDatabase, BloomGroupChain, GroupPosition, BloomGroup};
|
use bloomchain::group::{BloomGroupDatabase, BloomGroupChain, GroupPosition, BloomGroup};
|
||||||
@ -305,7 +305,7 @@ impl<T> TraceDatabase for TraceDB<T> where T: DatabaseExtras {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn trace(&self, block_number: BlockNumber, tx_position: usize, trace_position: Vec<usize>) -> Option<LocalizedTrace> {
|
fn trace(&self, block_number: BlockNumber, tx_position: usize, trace_position: Vec<usize>) -> Option<LocalizedTrace> {
|
||||||
let trace_position_deq = trace_position.into_iter().collect();
|
let trace_position_deq = trace_position.into_iter().collect::<VecDeque<usize>>();
|
||||||
self.extras.block_hash(block_number)
|
self.extras.block_hash(block_number)
|
||||||
.and_then(|block_hash| self.transactions_traces(&block_hash)
|
.and_then(|block_hash| self.transactions_traces(&block_hash)
|
||||||
.and_then(|traces| traces.into_iter().nth(tx_position))
|
.and_then(|traces| traces.into_iter().nth(tx_position))
|
||||||
|
@ -34,6 +34,8 @@ pub struct BlockChainInfo {
|
|||||||
pub best_block_hash: H256,
|
pub best_block_hash: H256,
|
||||||
/// Best blockchain block number.
|
/// Best blockchain block number.
|
||||||
pub best_block_number: BlockNumber,
|
pub best_block_number: BlockNumber,
|
||||||
|
/// Best blockchain block timestamp.
|
||||||
|
pub best_block_timestamp: u64,
|
||||||
/// Best ancient block hash.
|
/// Best ancient block hash.
|
||||||
pub ancient_block_hash: Option<H256>,
|
pub ancient_block_hash: Option<H256>,
|
||||||
/// Best ancient block number.
|
/// Best ancient block number.
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
use util::{Bytes, U256, Address, U512};
|
use util::{Bytes, U256, Address, U512};
|
||||||
use rlp::*;
|
use rlp::*;
|
||||||
|
use evm;
|
||||||
use trace::{VMTrace, FlatTrace};
|
use trace::{VMTrace, FlatTrace};
|
||||||
use types::log_entry::LogEntry;
|
use types::log_entry::LogEntry;
|
||||||
use types::state_diff::StateDiff;
|
use types::state_diff::StateDiff;
|
||||||
@ -65,6 +66,9 @@ impl Decodable for CallType {
|
|||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
#[cfg_attr(feature = "ipc", binary)]
|
#[cfg_attr(feature = "ipc", binary)]
|
||||||
pub struct Executed {
|
pub struct Executed {
|
||||||
|
/// True if the outer call/create resulted in an exceptional exit.
|
||||||
|
pub exception: Option<evm::Error>,
|
||||||
|
|
||||||
/// Gas paid up front for execution of transaction.
|
/// Gas paid up front for execution of transaction.
|
||||||
pub gas: U256,
|
pub gas: U256,
|
||||||
|
|
||||||
@ -178,6 +182,8 @@ pub enum CallError {
|
|||||||
TransactionNotFound,
|
TransactionNotFound,
|
||||||
/// Couldn't find requested block's state in the chain.
|
/// Couldn't find requested block's state in the chain.
|
||||||
StatePruned,
|
StatePruned,
|
||||||
|
/// Couldn't find an amount of gas that didn't result in an exception.
|
||||||
|
Exceptional,
|
||||||
/// Error executing.
|
/// Error executing.
|
||||||
Execution(ExecutionError),
|
Execution(ExecutionError),
|
||||||
}
|
}
|
||||||
@ -195,6 +201,7 @@ impl fmt::Display for CallError {
|
|||||||
let msg = match *self {
|
let msg = match *self {
|
||||||
TransactionNotFound => "Transaction couldn't be found in the chain".into(),
|
TransactionNotFound => "Transaction couldn't be found in the chain".into(),
|
||||||
StatePruned => "Couldn't find the transaction block's state in the chain".into(),
|
StatePruned => "Couldn't find the transaction block's state in the chain".into(),
|
||||||
|
Exceptional => "An exception happened in the execution".into(),
|
||||||
Execution(ref e) => format!("{}", e),
|
Execution(ref e) => format!("{}", e),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -391,6 +391,14 @@ impl Res {
|
|||||||
Res::Call(_) | Res::FailedCall(_) | Res::FailedCreate(_) | Res::None => Default::default(),
|
Res::Call(_) | Res::FailedCall(_) | Res::FailedCreate(_) | Res::None => Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Did this call fail?
|
||||||
|
pub fn succeeded(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
Res::Call(_) | Res::Create(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
@ -561,4 +569,3 @@ impl Decodable for VMTrace {
|
|||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
//! Transaction data structure.
|
//! Transaction data structure.
|
||||||
|
|
||||||
use std::ops::Deref;
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::cell::*;
|
use std::cell::*;
|
||||||
use rlp::*;
|
use rlp::*;
|
||||||
use util::sha3::Hashable;
|
use util::sha3::Hashable;
|
||||||
@ -53,6 +53,16 @@ impl Decodable for Action {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Transaction activation condition.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "ipc", binary)]
|
||||||
|
pub enum Condition {
|
||||||
|
/// Valid at this block number or later.
|
||||||
|
Number(BlockNumber),
|
||||||
|
/// Valid at this unix time or later.
|
||||||
|
Timestamp(u64),
|
||||||
|
}
|
||||||
|
|
||||||
/// A set of information describing an externally-originating message call
|
/// A set of information describing an externally-originating message call
|
||||||
/// or contract creation operation.
|
/// or contract creation operation.
|
||||||
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
||||||
@ -102,6 +112,7 @@ impl HeapSizeOf for Transaction {
|
|||||||
impl From<ethjson::state::Transaction> for SignedTransaction {
|
impl From<ethjson::state::Transaction> for SignedTransaction {
|
||||||
fn from(t: ethjson::state::Transaction) -> Self {
|
fn from(t: ethjson::state::Transaction) -> Self {
|
||||||
let to: Option<ethjson::hash::Address> = t.to.into();
|
let to: Option<ethjson::hash::Address> = t.to.into();
|
||||||
|
let secret = Secret::from_slice(&t.secret.0).expect("Valid secret expected.");
|
||||||
Transaction {
|
Transaction {
|
||||||
nonce: t.nonce.into(),
|
nonce: t.nonce.into(),
|
||||||
gas_price: t.gas_price.into(),
|
gas_price: t.gas_price.into(),
|
||||||
@ -112,7 +123,7 @@ impl From<ethjson::state::Transaction> for SignedTransaction {
|
|||||||
},
|
},
|
||||||
value: t.value.into(),
|
value: t.value.into(),
|
||||||
data: t.data.into(),
|
data: t.data.into(),
|
||||||
}.sign(&t.secret.into(), None)
|
}.sign(&secret, None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,6 +250,12 @@ impl Deref for SignedTransaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DerefMut for SignedTransaction {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.unsigned
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Decodable for SignedTransaction {
|
impl Decodable for SignedTransaction {
|
||||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||||
let d = decoder.as_rlp();
|
let d = decoder.as_rlp();
|
||||||
@ -400,16 +417,16 @@ impl Deref for LocalizedTransaction {
|
|||||||
pub struct PendingTransaction {
|
pub struct PendingTransaction {
|
||||||
/// Signed transaction data.
|
/// Signed transaction data.
|
||||||
pub transaction: SignedTransaction,
|
pub transaction: SignedTransaction,
|
||||||
/// To be activated at this block. `None` for immediately.
|
/// To be activated at this condition. `None` for immediately.
|
||||||
pub min_block: Option<BlockNumber>,
|
pub condition: Option<Condition>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PendingTransaction {
|
impl PendingTransaction {
|
||||||
/// Create a new pending transaction from signed transaction.
|
/// Create a new pending transaction from signed transaction.
|
||||||
pub fn new(signed: SignedTransaction, min_block: Option<BlockNumber>) -> Self {
|
pub fn new(signed: SignedTransaction, condition: Option<Condition>) -> Self {
|
||||||
PendingTransaction {
|
PendingTransaction {
|
||||||
transaction: signed,
|
transaction: signed,
|
||||||
min_block: min_block,
|
condition: condition,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -418,7 +435,7 @@ impl From<SignedTransaction> for PendingTransaction {
|
|||||||
fn from(t: SignedTransaction) -> Self {
|
fn from(t: SignedTransaction) -> Self {
|
||||||
PendingTransaction {
|
PendingTransaction {
|
||||||
transaction: t,
|
transaction: t,
|
||||||
min_block: None,
|
condition: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,7 +186,7 @@ pub mod headers {
|
|||||||
type Verified = Header;
|
type Verified = Header;
|
||||||
|
|
||||||
fn create(input: Self::Input, engine: &Engine) -> Result<Self::Unverified, Error> {
|
fn create(input: Self::Input, engine: &Engine) -> Result<Self::Unverified, Error> {
|
||||||
verify_header_params(&input, engine).map(|_| input)
|
verify_header_params(&input, engine, true).map(|_| input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify(unverified: Self::Unverified, engine: &Engine, check_seal: bool) -> Result<Self::Verified, Error> {
|
fn verify(unverified: Self::Unverified, engine: &Engine, check_seal: bool) -> Result<Self::Verified, Error> {
|
||||||
|
@ -51,12 +51,12 @@ impl HeapSizeOf for PreverifiedBlock {
|
|||||||
|
|
||||||
/// Phase 1 quick block verification. Only does checks that are cheap. Operates on a single block
|
/// Phase 1 quick block verification. Only does checks that are cheap. Operates on a single block
|
||||||
pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &Engine) -> Result<(), Error> {
|
pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &Engine) -> Result<(), Error> {
|
||||||
verify_header_params(&header, engine)?;
|
verify_header_params(&header, engine, true)?;
|
||||||
verify_block_integrity(bytes, &header.transactions_root(), &header.uncles_hash())?;
|
verify_block_integrity(bytes, &header.transactions_root(), &header.uncles_hash())?;
|
||||||
engine.verify_block_basic(&header, Some(bytes))?;
|
engine.verify_block_basic(&header, Some(bytes))?;
|
||||||
for u in UntrustedRlp::new(bytes).at(2)?.iter().map(|rlp| rlp.as_val::<Header>()) {
|
for u in UntrustedRlp::new(bytes).at(2)?.iter().map(|rlp| rlp.as_val::<Header>()) {
|
||||||
let u = u?;
|
let u = u?;
|
||||||
verify_header_params(&u, engine)?;
|
verify_header_params(&u, engine, false)?;
|
||||||
engine.verify_block_basic(&u, None)?;
|
engine.verify_block_basic(&u, None)?;
|
||||||
}
|
}
|
||||||
// Verify transactions.
|
// Verify transactions.
|
||||||
@ -195,7 +195,7 @@ pub fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check basic header parameters.
|
/// Check basic header parameters.
|
||||||
pub fn verify_header_params(header: &Header, engine: &Engine) -> Result<(), Error> {
|
pub fn verify_header_params(header: &Header, engine: &Engine, is_full: bool) -> Result<(), Error> {
|
||||||
if header.number() >= From::from(BlockNumber::max_value()) {
|
if header.number() >= From::from(BlockNumber::max_value()) {
|
||||||
return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { max: Some(From::from(BlockNumber::max_value())), min: None, found: header.number() })))
|
return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { max: Some(From::from(BlockNumber::max_value())), min: None, found: header.number() })))
|
||||||
}
|
}
|
||||||
@ -210,10 +210,12 @@ pub fn verify_header_params(header: &Header, engine: &Engine) -> Result<(), Erro
|
|||||||
if header.number() != 0 && header.extra_data().len() > maximum_extra_data_size {
|
if header.number() != 0 && header.extra_data().len() > maximum_extra_data_size {
|
||||||
return Err(From::from(BlockError::ExtraDataOutOfBounds(OutOfBounds { min: None, max: Some(maximum_extra_data_size), found: header.extra_data().len() })));
|
return Err(From::from(BlockError::ExtraDataOutOfBounds(OutOfBounds { min: None, max: Some(maximum_extra_data_size), found: header.extra_data().len() })));
|
||||||
}
|
}
|
||||||
|
if is_full {
|
||||||
let max_time = get_time().sec as u64 + 30;
|
let max_time = get_time().sec as u64 + 30;
|
||||||
if header.timestamp() > max_time {
|
if header.timestamp() > max_time {
|
||||||
return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: Some(max_time), min: None, found: header.timestamp() })))
|
return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: Some(max_time), min: None, found: header.timestamp() })))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +166,7 @@ pub mod aes {
|
|||||||
/// ECDH functions
|
/// ECDH functions
|
||||||
#[cfg_attr(feature="dev", allow(similar_names))]
|
#[cfg_attr(feature="dev", allow(similar_names))]
|
||||||
pub mod ecdh {
|
pub mod ecdh {
|
||||||
use secp256k1::{ecdh, key};
|
use secp256k1::{ecdh, key, Error as SecpError};
|
||||||
use ethkey::{Secret, Public, SECP256K1};
|
use ethkey::{Secret, Public, SECP256K1};
|
||||||
use Error;
|
use Error;
|
||||||
|
|
||||||
@ -180,13 +180,11 @@ pub mod ecdh {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let publ = key::PublicKey::from_slice(context, &pdata)?;
|
let publ = key::PublicKey::from_slice(context, &pdata)?;
|
||||||
// no way to create SecretKey from raw byte array.
|
let sec = key::SecretKey::from_slice(context, &secret)?;
|
||||||
let sec: &key::SecretKey = unsafe { ::std::mem::transmute(secret) };
|
let shared = ecdh::SharedSecret::new_raw(context, &publ, &sec);
|
||||||
let shared = ecdh::SharedSecret::new_raw(context, &publ, sec);
|
|
||||||
|
|
||||||
let mut s = Secret::default();
|
Secret::from_slice(&shared[0..32])
|
||||||
s.copy_from_slice(&shared[0..32]);
|
.map_err(|_| Error::Secp(SecpError::InvalidSecretKey))
|
||||||
Ok(s)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use keccak::Keccak256;
|
use keccak::Keccak256;
|
||||||
use super::{KeyPair, Error, Generator};
|
use super::{KeyPair, Error, Generator, Secret};
|
||||||
|
|
||||||
/// Simple brainwallet.
|
/// Simple brainwallet.
|
||||||
pub struct Brain(String);
|
pub struct Brain(String);
|
||||||
@ -38,10 +38,12 @@ impl Generator for Brain {
|
|||||||
match i > 16384 {
|
match i > 16384 {
|
||||||
false => i += 1,
|
false => i += 1,
|
||||||
true => {
|
true => {
|
||||||
let result = KeyPair::from_secret(secret.clone().into());
|
if let Ok(secret) = Secret::from_slice(&secret) {
|
||||||
|
let result = KeyPair::from_secret(secret);
|
||||||
if result.as_ref().ok().map_or(false, |r| r.address()[0] == 0) {
|
if result.as_ref().ok().map_or(false, |r| r.address()[0] == 0) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,11 +60,14 @@ impl KeyPair {
|
|||||||
Ok(keypair)
|
Ok(keypair)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_secret_slice(slice: &[u8]) -> Result<KeyPair, Error> {
|
||||||
|
Self::from_secret(Secret::from_slice(slice)?)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_keypair(sec: key::SecretKey, publ: key::PublicKey) -> Self {
|
pub fn from_keypair(sec: key::SecretKey, publ: key::PublicKey) -> Self {
|
||||||
let context = &SECP256K1;
|
let context = &SECP256K1;
|
||||||
let serialized = publ.serialize_vec(context, false);
|
let serialized = publ.serialize_vec(context, false);
|
||||||
let mut secret = Secret::default();
|
let secret = Secret::from(sec);
|
||||||
secret.copy_from_slice(&sec[0..32]);
|
|
||||||
let mut public = Public::default();
|
let mut public = Public::default();
|
||||||
public.copy_from_slice(&serialized[1..65]);
|
public.copy_from_slice(&serialized[1..65]);
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ mod keccak;
|
|||||||
mod prefix;
|
mod prefix;
|
||||||
mod random;
|
mod random;
|
||||||
mod signature;
|
mod signature;
|
||||||
|
mod secret;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref SECP256K1: secp256k1::Secp256k1 = secp256k1::Secp256k1::new();
|
pub static ref SECP256K1: secp256k1::Secp256k1 = secp256k1::Secp256k1::new();
|
||||||
@ -46,10 +47,10 @@ pub use self::keypair::{KeyPair, public_to_address};
|
|||||||
pub use self::prefix::Prefix;
|
pub use self::prefix::Prefix;
|
||||||
pub use self::random::Random;
|
pub use self::random::Random;
|
||||||
pub use self::signature::{sign, verify_public, verify_address, recover, Signature};
|
pub use self::signature::{sign, verify_public, verify_address, recover, Signature};
|
||||||
|
pub use self::secret::Secret;
|
||||||
|
|
||||||
use bigint::hash::{H160, H256, H512};
|
use bigint::hash::{H160, H256, H512};
|
||||||
|
|
||||||
pub type Address = H160;
|
pub type Address = H160;
|
||||||
pub type Secret = H256;
|
|
||||||
pub type Message = H256;
|
pub type Message = H256;
|
||||||
pub type Public = H512;
|
pub type Public = H512;
|
||||||
|
69
ethkey/src/secret.rs
Normal file
69
ethkey/src/secret.rs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// Copyright 2015, 2016 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/>.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use secp256k1::key;
|
||||||
|
use bigint::hash::H256;
|
||||||
|
use {Error};
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
|
pub struct Secret {
|
||||||
|
inner: H256,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Secret {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(fmt, "Secret: 0x{:x}{:x}..{:x}{:x}", self.inner[0], self.inner[1], self.inner[30], self.inner[31])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Secret {
|
||||||
|
pub fn from_slice(key: &[u8]) -> Result<Self, Error> {
|
||||||
|
if key.len() != 32 {
|
||||||
|
return Err(Error::InvalidSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut h = H256::default();
|
||||||
|
h.copy_from_slice(&key[0..32]);
|
||||||
|
Ok(Secret { inner: h })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Secret {
|
||||||
|
type Err = Error;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let hash = H256::from_str(s).map_err(|e| Error::Custom(format!("{:?}", e)))?;
|
||||||
|
Self::from_slice(&hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<key::SecretKey> for Secret {
|
||||||
|
fn from(key: key::SecretKey) -> Self {
|
||||||
|
Self::from_slice(&key[0..32])
|
||||||
|
.expect("`key::SecretKey` is valid (no way to construct invalid one); qed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Secret {
|
||||||
|
type Target = H256;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::cmp::PartialEq;
|
use std::cmp::PartialEq;
|
||||||
use std::{mem, fmt};
|
use std::fmt;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use secp256k1::{Message as SecpMessage, RecoverableSignature, RecoveryId, Error as SecpError};
|
use secp256k1::{Message as SecpMessage, RecoverableSignature, RecoveryId, Error as SecpError};
|
||||||
@ -169,9 +169,8 @@ impl DerefMut for Signature {
|
|||||||
|
|
||||||
pub fn sign(secret: &Secret, message: &Message) -> Result<Signature, Error> {
|
pub fn sign(secret: &Secret, message: &Message) -> Result<Signature, Error> {
|
||||||
let context = &SECP256K1;
|
let context = &SECP256K1;
|
||||||
// no way to create from raw byte array.
|
let sec = SecretKey::from_slice(context, &secret)?;
|
||||||
let sec: &SecretKey = unsafe { mem::transmute(secret) };
|
let s = context.sign_recoverable(&SecpMessage::from_slice(&message[..])?, &sec)?;
|
||||||
let s = context.sign_recoverable(&SecpMessage::from_slice(&message[..])?, sec)?;
|
|
||||||
let (rec_id, data) = s.serialize_compact(context);
|
let (rec_id, data) = s.serialize_compact(context);
|
||||||
let mut data_arr = [0; 65];
|
let mut data_arr = [0; 65];
|
||||||
|
|
||||||
|
@ -122,16 +122,14 @@ impl Crypto {
|
|||||||
return Err(Error::InvalidPassword);
|
return Err(Error::InvalidPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut secret = Secret::default();
|
|
||||||
|
|
||||||
match self.cipher {
|
match self.cipher {
|
||||||
Cipher::Aes128Ctr(ref params) => {
|
Cipher::Aes128Ctr(ref params) => {
|
||||||
let from = 32 - self.ciphertext.len();
|
let from = 32 - self.ciphertext.len();
|
||||||
crypto::aes::decrypt(&derived_left_bits, ¶ms.iv, &self.ciphertext, &mut (&mut *secret)[from..])
|
let mut secret = [0; 32];
|
||||||
|
crypto::aes::decrypt(&derived_left_bits, ¶ms.iv, &self.ciphertext, &mut secret[from..]);
|
||||||
|
Ok(Secret::from_slice(&secret)?)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(secret)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,7 +271,9 @@ impl SimpleSecretStore for EthMultiStore {
|
|||||||
// Remove from cache
|
// Remove from cache
|
||||||
let mut cache = self.cache.write();
|
let mut cache = self.cache.write();
|
||||||
let is_empty = {
|
let is_empty = {
|
||||||
let mut accounts = cache.get_mut(address).expect("Entry exists, because it was returned by `get`; qed");
|
let mut accounts = cache.get_mut(address)
|
||||||
|
.ok_or(Error::InvalidAccount)?;
|
||||||
|
|
||||||
if let Some(position) = accounts.iter().position(|acc| acc == &account) {
|
if let Some(position) = accounts.iter().position(|acc| acc == &account) {
|
||||||
accounts.remove(position);
|
accounts.remove(position);
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ impl PresaleWallet {
|
|||||||
let len = crypto::aes::decrypt_cbc(&derived_key, &self.iv, &self.ciphertext, &mut key).map_err(|_| Error::InvalidPassword)?;
|
let len = crypto::aes::decrypt_cbc(&derived_key, &self.iv, &self.ciphertext, &mut key).map_err(|_| Error::InvalidPassword)?;
|
||||||
let unpadded = &key[..len];
|
let unpadded = &key[..len];
|
||||||
|
|
||||||
let secret = Secret::from(unpadded.keccak256());
|
let secret = Secret::from_slice(&unpadded.keccak256())?;
|
||||||
if let Ok(kp) = KeyPair::from_secret(secret) {
|
if let Ok(kp) = KeyPair::from_secret(secret) {
|
||||||
if kp.address() == self.address {
|
if kp.address() == self.address {
|
||||||
return Ok(kp)
|
return Ok(kp)
|
||||||
|
@ -133,9 +133,9 @@ fn secret_store_load_pat_files() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_decrypting_files_with_short_ciphertext() {
|
fn test_decrypting_files_with_short_ciphertext() {
|
||||||
// 31e9d1e6d844bd3a536800ef8d8be6a9975db509, 30
|
// 31e9d1e6d844bd3a536800ef8d8be6a9975db509, 30
|
||||||
let kp1 = KeyPair::from_secret("000081c29e8142bb6a81bef5a92bda7a8328a5c85bb2f9542e76f9b0f94fc018".into()).unwrap();
|
let kp1 = KeyPair::from_secret("000081c29e8142bb6a81bef5a92bda7a8328a5c85bb2f9542e76f9b0f94fc018".parse().unwrap()).unwrap();
|
||||||
// d1e64e5480bfaf733ba7d48712decb8227797a4e , 31
|
// d1e64e5480bfaf733ba7d48712decb8227797a4e , 31
|
||||||
let kp2 = KeyPair::from_secret("00fa7b3db73dc7dfdf8c5fbdb796d741e4488628c41fc4febd9160a866ba0f35".into()).unwrap();
|
let kp2 = KeyPair::from_secret("00fa7b3db73dc7dfdf8c5fbdb796d741e4488628c41fc4febd9160a866ba0f35".parse().unwrap()).unwrap();
|
||||||
let dir = DiskDirectory::at(ciphertext_path());
|
let dir = DiskDirectory::at(ciphertext_path());
|
||||||
let store = EthStore::open(Box::new(dir)).unwrap();
|
let store = EthStore::open(Box::new(dir)).unwrap();
|
||||||
let accounts = store.accounts().unwrap();
|
let accounts = store.accounts().unwrap();
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "evm"
|
name = "evmbin"
|
||||||
description = "Parity's EVM implementation"
|
description = "Parity's EVM implementation"
|
||||||
version = "0.1.0"
|
version = "1.5.0"
|
||||||
authors = ["Parity Technologies <admin@parity.io>"]
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
@ -31,7 +31,7 @@ pub struct FakeExt {
|
|||||||
impl Default for FakeExt {
|
impl Default for FakeExt {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
FakeExt {
|
FakeExt {
|
||||||
schedule: Schedule::new_homestead_gas_fix(),
|
schedule: Schedule::new_post_eip150(usize::max_value(), true, true, true),
|
||||||
store: HashMap::new(),
|
store: HashMap::new(),
|
||||||
depth: 1,
|
depth: 1,
|
||||||
}
|
}
|
||||||
@ -51,7 +51,7 @@ impl Ext for FakeExt {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exists_and_not_null(&self, address: &Address) -> bool {
|
fn exists_and_not_null(&self, _address: &Address) -> bool {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
extern crate ethcore;
|
extern crate ethcore;
|
||||||
extern crate rustc_serialize;
|
extern crate rustc_serialize;
|
||||||
extern crate docopt;
|
extern crate docopt;
|
||||||
#[macro_use]
|
|
||||||
extern crate ethcore_util as util;
|
extern crate ethcore_util as util;
|
||||||
|
|
||||||
mod ext;
|
mod ext;
|
||||||
|
@ -17,8 +17,9 @@
|
|||||||
//! Types used in the public API
|
//! Types used in the public API
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::str::FromStr;
|
||||||
use semver::{Version};
|
use semver::{Version};
|
||||||
use util::{H160};
|
use util::{H160, FixedHash};
|
||||||
use util::misc::raw_package_info;
|
use util::misc::raw_package_info;
|
||||||
use release_track::ReleaseTrack;
|
use release_track::ReleaseTrack;
|
||||||
|
|
||||||
@ -47,7 +48,7 @@ impl VersionInfo {
|
|||||||
VersionInfo {
|
VersionInfo {
|
||||||
track: raw.0.into(),
|
track: raw.0.into(),
|
||||||
version: { let mut v = Version::parse(raw.1).expect("Environment variables are known to be valid; qed"); v.build = vec![]; v.pre = vec![]; v },
|
version: { let mut v = Version::parse(raw.1).expect("Environment variables are known to be valid; qed"); v.build = vec![]; v.pre = vec![]; v },
|
||||||
hash: raw.2.into(),
|
hash: H160::from_str(raw.2).unwrap_or_else(|_| H160::zero()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
font-family: 'Roboto';
|
font-family: 'Roboto';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src: local('Roboto Light'), local('Roboto-Light'), url(v15/0eC6fl06luXEYWpBSJvXCIX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
|
src: local('Roboto Light'), local('Roboto-Light'), url(./v15/0eC6fl06luXEYWpBSJvXCIX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
|
||||||
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
|
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
|
||||||
}
|
}
|
||||||
/* cyrillic */
|
/* cyrillic */
|
||||||
@ -11,7 +11,7 @@
|
|||||||
font-family: 'Roboto';
|
font-family: 'Roboto';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src: local('Roboto Light'), local('Roboto-Light'), url(v15/Fl4y0QdOxyyTHEGMXX8kcYX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
|
src: local('Roboto Light'), local('Roboto-Light'), url(./v15/Fl4y0QdOxyyTHEGMXX8kcYX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
|
||||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
}
|
}
|
||||||
/* greek-ext */
|
/* greek-ext */
|
||||||
@ -19,7 +19,7 @@
|
|||||||
font-family: 'Roboto';
|
font-family: 'Roboto';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src: local('Roboto Light'), local('Roboto-Light'), url(v15/-L14Jk06m6pUHB-5mXQQnYX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
|
src: local('Roboto Light'), local('Roboto-Light'), url(./v15/-L14Jk06m6pUHB-5mXQQnYX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
|
||||||
unicode-range: U+1F00-1FFF;
|
unicode-range: U+1F00-1FFF;
|
||||||
}
|
}
|
||||||
/* greek */
|
/* greek */
|
||||||
@ -27,7 +27,7 @@
|
|||||||
font-family: 'Roboto';
|
font-family: 'Roboto';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src: local('Roboto Light'), local('Roboto-Light'), url(v15/I3S1wsgSg9YCurV6PUkTOYX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
|
src: local('Roboto Light'), local('Roboto-Light'), url(./v15/I3S1wsgSg9YCurV6PUkTOYX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
|
||||||
unicode-range: U+0370-03FF;
|
unicode-range: U+0370-03FF;
|
||||||
}
|
}
|
||||||
/* vietnamese */
|
/* vietnamese */
|
||||||
@ -35,7 +35,7 @@
|
|||||||
font-family: 'Roboto';
|
font-family: 'Roboto';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src: local('Roboto Light'), local('Roboto-Light'), url(v15/NYDWBdD4gIq26G5XYbHsFIX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
|
src: local('Roboto Light'), local('Roboto-Light'), url(./v15/NYDWBdD4gIq26G5XYbHsFIX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
|
||||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||||
}
|
}
|
||||||
/* latin-ext */
|
/* latin-ext */
|
||||||
@ -43,7 +43,7 @@
|
|||||||
font-family: 'Roboto';
|
font-family: 'Roboto';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src: local('Roboto Light'), local('Roboto-Light'), url(v15/Pru33qjShpZSmG3z6VYwnYX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
|
src: local('Roboto Light'), local('Roboto-Light'), url(./v15/Pru33qjShpZSmG3z6VYwnYX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
|
||||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||||
}
|
}
|
||||||
/* latin */
|
/* latin */
|
||||||
@ -51,6 +51,6 @@
|
|||||||
font-family: 'Roboto';
|
font-family: 'Roboto';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src: local('Roboto Light'), local('Roboto-Light'), url(v15/Hgo13k-tfSpn0qi1SFdUfZBw1xU1rKptJj_0jans920.woff2) format('woff2');
|
src: local('Roboto Light'), local('Roboto-Light'), url(./v15/Hgo13k-tfSpn0qi1SFdUfZBw1xU1rKptJj_0jans920.woff2) format('woff2');
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
font-family: 'Roboto Mono';
|
font-family: 'Roboto Mono';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src: local('Roboto Mono Light'), local('RobotoMono-Light'), url(v4/N4duVc9C58uwPiY8_59Fz0ExlR2MysFCBK8OirNw2kM.woff2) format('woff2');
|
src: local('Roboto Mono Light'), local('RobotoMono-Light'), url(./v4/N4duVc9C58uwPiY8_59Fz0ExlR2MysFCBK8OirNw2kM.woff2) format('woff2');
|
||||||
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
|
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
|
||||||
}
|
}
|
||||||
/* cyrillic */
|
/* cyrillic */
|
||||||
@ -11,7 +11,7 @@
|
|||||||
font-family: 'Roboto Mono';
|
font-family: 'Roboto Mono';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src: local('Roboto Mono Light'), local('RobotoMono-Light'), url(v4/N4duVc9C58uwPiY8_59Fz2dsm03krrxlabhmVQFB99s.woff2) format('woff2');
|
src: local('Roboto Mono Light'), local('RobotoMono-Light'), url(./v4/N4duVc9C58uwPiY8_59Fz2dsm03krrxlabhmVQFB99s.woff2) format('woff2');
|
||||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
}
|
}
|
||||||
/* greek-ext */
|
/* greek-ext */
|
||||||
@ -19,7 +19,7 @@
|
|||||||
font-family: 'Roboto Mono';
|
font-family: 'Roboto Mono';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src: local('Roboto Mono Light'), local('RobotoMono-Light'), url(v4/N4duVc9C58uwPiY8_59FzyJ0caWjaSBdV-xZbEgst_k.woff2) format('woff2');
|
src: local('Roboto Mono Light'), local('RobotoMono-Light'), url(./v4/N4duVc9C58uwPiY8_59FzyJ0caWjaSBdV-xZbEgst_k.woff2) format('woff2');
|
||||||
unicode-range: U+1F00-1FFF;
|
unicode-range: U+1F00-1FFF;
|
||||||
}
|
}
|
||||||
/* greek */
|
/* greek */
|
||||||
@ -27,7 +27,7 @@
|
|||||||
font-family: 'Roboto Mono';
|
font-family: 'Roboto Mono';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src: local('Roboto Mono Light'), local('RobotoMono-Light'), url(v4/N4duVc9C58uwPiY8_59Fz2MSHb9EAJwuSzGfuRChQzQ.woff2) format('woff2');
|
src: local('Roboto Mono Light'), local('RobotoMono-Light'), url(./v4/N4duVc9C58uwPiY8_59Fz2MSHb9EAJwuSzGfuRChQzQ.woff2) format('woff2');
|
||||||
unicode-range: U+0370-03FF;
|
unicode-range: U+0370-03FF;
|
||||||
}
|
}
|
||||||
/* vietnamese */
|
/* vietnamese */
|
||||||
@ -35,7 +35,7 @@
|
|||||||
font-family: 'Roboto Mono';
|
font-family: 'Roboto Mono';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src: local('Roboto Mono Light'), local('RobotoMono-Light'), url(v4/N4duVc9C58uwPiY8_59Fz-pRBTtN4E2_qSPBnw6AgMc.woff2) format('woff2');
|
src: local('Roboto Mono Light'), local('RobotoMono-Light'), url(./v4/N4duVc9C58uwPiY8_59Fz-pRBTtN4E2_qSPBnw6AgMc.woff2) format('woff2');
|
||||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||||
}
|
}
|
||||||
/* latin-ext */
|
/* latin-ext */
|
||||||
@ -43,7 +43,7 @@
|
|||||||
font-family: 'Roboto Mono';
|
font-family: 'Roboto Mono';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src: local('Roboto Mono Light'), local('RobotoMono-Light'), url(v4/N4duVc9C58uwPiY8_59Fz9Dnm4qiMZlH5rhYv_7LI2Y.woff2) format('woff2');
|
src: local('Roboto Mono Light'), local('RobotoMono-Light'), url(./v4/N4duVc9C58uwPiY8_59Fz9Dnm4qiMZlH5rhYv_7LI2Y.woff2) format('woff2');
|
||||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||||
}
|
}
|
||||||
/* latin */
|
/* latin */
|
||||||
@ -51,6 +51,6 @@
|
|||||||
font-family: 'Roboto Mono';
|
font-family: 'Roboto Mono';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src: local('Roboto Mono Light'), local('RobotoMono-Light'), url(v4/N4duVc9C58uwPiY8_59Fz9TIkQYohD4BpHvJ3NvbHoA.woff2) format('woff2');
|
src: local('Roboto Mono Light'), local('RobotoMono-Light'), url(./v4/N4duVc9C58uwPiY8_59Fz9TIkQYohD4BpHvJ3NvbHoA.woff2) format('woff2');
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||||
}
|
}
|
||||||
|
@ -163,6 +163,7 @@
|
|||||||
"phoneformat.js": "1.0.3",
|
"phoneformat.js": "1.0.3",
|
||||||
"promise-worker": "1.1.1",
|
"promise-worker": "1.1.1",
|
||||||
"push.js": "0.0.11",
|
"push.js": "0.0.11",
|
||||||
|
"qrcode-npm": "0.0.3",
|
||||||
"qs": "6.3.0",
|
"qs": "6.3.0",
|
||||||
"react": "15.4.1",
|
"react": "15.4.1",
|
||||||
"react-ace": "4.1.0",
|
"react-ace": "4.1.0",
|
||||||
@ -170,6 +171,8 @@
|
|||||||
"react-copy-to-clipboard": "4.2.3",
|
"react-copy-to-clipboard": "4.2.3",
|
||||||
"react-dom": "15.4.1",
|
"react-dom": "15.4.1",
|
||||||
"react-dropzone": "3.7.3",
|
"react-dropzone": "3.7.3",
|
||||||
|
"react-element-to-jsx-string": "6.0.0",
|
||||||
|
"react-event-listener": "0.4.1",
|
||||||
"react-intl": "2.1.5",
|
"react-intl": "2.1.5",
|
||||||
"react-portal": "3.0.0",
|
"react-portal": "3.0.0",
|
||||||
"react-redux": "4.4.6",
|
"react-redux": "4.4.6",
|
||||||
@ -185,10 +188,13 @@
|
|||||||
"scryptsy": "2.0.0",
|
"scryptsy": "2.0.0",
|
||||||
"solc": "ngotchac/solc-js",
|
"solc": "ngotchac/solc-js",
|
||||||
"store": "1.3.20",
|
"store": "1.3.20",
|
||||||
|
"uglify-js": "2.8.2",
|
||||||
|
"useragent.js": "0.5.6",
|
||||||
"utf8": "2.1.2",
|
"utf8": "2.1.2",
|
||||||
"valid-url": "1.0.9",
|
"valid-url": "1.0.9",
|
||||||
"validator": "6.2.0",
|
"validator": "6.2.0",
|
||||||
"web3": "0.17.0-beta",
|
"web3": "0.17.0-beta",
|
||||||
"whatwg-fetch": "2.0.1"
|
"whatwg-fetch": "2.0.1",
|
||||||
|
"zxcvbn": "4.4.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
js/src/3rdparty/email-verification/index.js
vendored
13
js/src/3rdparty/email-verification/index.js
vendored
@ -16,6 +16,19 @@
|
|||||||
|
|
||||||
import { stringify } from 'querystring';
|
import { stringify } from 'querystring';
|
||||||
|
|
||||||
|
export const isServerRunning = (isTestnet = false) => {
|
||||||
|
const port = isTestnet ? 28443 : 18443;
|
||||||
|
return fetch(`https://email-verification.parity.io:${port}/health`, {
|
||||||
|
mode: 'cors', cache: 'no-store'
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
return res.ok;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const postToServer = (query, isTestnet = false) => {
|
export const postToServer = (query, isTestnet = false) => {
|
||||||
const port = isTestnet ? 28443 : 18443;
|
const port = isTestnet ? 28443 : 18443;
|
||||||
query = stringify(query);
|
query = stringify(query);
|
||||||
|
22
js/src/3rdparty/etherscan/account.js
vendored
22
js/src/3rdparty/etherscan/account.js
vendored
@ -21,15 +21,15 @@ const PAGE_SIZE = 25;
|
|||||||
import util from '../../api/util';
|
import util from '../../api/util';
|
||||||
import { call } from './call';
|
import { call } from './call';
|
||||||
|
|
||||||
function _call (method, params, test) {
|
function _call (method, params, test, netVersion) {
|
||||||
return call('account', method, params, test);
|
return call('account', method, params, test, netVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
function balance (address, test = false) {
|
function balance (address, test, netVersion) {
|
||||||
return _call('balance', {
|
return _call('balance', {
|
||||||
address: address,
|
address: address,
|
||||||
tag: 'latest'
|
tag: 'latest'
|
||||||
}, test).then((balance) => {
|
}, test, netVersion).then((balance) => {
|
||||||
// same format as balancemulti below
|
// same format as balancemulti below
|
||||||
return {
|
return {
|
||||||
account: address,
|
account: address,
|
||||||
@ -38,21 +38,21 @@ function balance (address, test = false) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function balances (addresses, test = false) {
|
function balances (addresses, test, netVersion) {
|
||||||
return _call('balancemulti', {
|
return _call('balancemulti', {
|
||||||
address: addresses.join(','),
|
address: addresses.join(','),
|
||||||
tag: 'latest'
|
tag: 'latest'
|
||||||
}, test);
|
}, test, netVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
function transactions (address, page, test = false) {
|
function transactions (address, page, test, netVersion) {
|
||||||
// page offset from 0
|
// page offset from 0
|
||||||
return _call('txlist', {
|
return _call('txlist', {
|
||||||
address: address,
|
address: address,
|
||||||
offset: PAGE_SIZE,
|
offset: PAGE_SIZE,
|
||||||
page: (page || 0) + 1,
|
page: (page || 0) + 1,
|
||||||
sort: 'desc'
|
sort: 'desc'
|
||||||
}, test).then((transactions) => {
|
}, test, netVersion).then((transactions) => {
|
||||||
return transactions.map((tx) => {
|
return transactions.map((tx) => {
|
||||||
return {
|
return {
|
||||||
blockNumber: new BigNumber(tx.blockNumber || 0),
|
blockNumber: new BigNumber(tx.blockNumber || 0),
|
||||||
@ -67,9 +67,9 @@ function transactions (address, page, test = false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const account = {
|
const account = {
|
||||||
balance: balance,
|
balance,
|
||||||
balances: balances,
|
balances,
|
||||||
transactions: transactions
|
transactions
|
||||||
};
|
};
|
||||||
|
|
||||||
export { account };
|
export { account };
|
||||||
|
24
js/src/3rdparty/etherscan/call.js
vendored
24
js/src/3rdparty/etherscan/call.js
vendored
@ -23,14 +23,32 @@ const options = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export function call (module, action, _params, test) {
|
export function call (module, action, _params, test, netVersion) {
|
||||||
const host = test ? 'testnet.etherscan.io' : 'api.etherscan.io';
|
let prefix = 'api.';
|
||||||
|
|
||||||
|
switch (netVersion) {
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
prefix = 'testnet.';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '42':
|
||||||
|
prefix = 'kovan.';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '0':
|
||||||
|
default:
|
||||||
|
if (test) {
|
||||||
|
prefix = 'testnet.';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
const query = stringify(Object.assign({
|
const query = stringify(Object.assign({
|
||||||
module, action
|
module, action
|
||||||
}, _params || {}));
|
}, _params || {}));
|
||||||
|
|
||||||
return fetch(`https://${host}/api?${query}`, options)
|
return fetch(`https://${prefix}etherscan.io/api?${query}`, options)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw { code: response.status, message: response.statusText }; // eslint-disable-line
|
throw { code: response.status, message: response.statusText }; // eslint-disable-line
|
||||||
|
4
js/src/3rdparty/etherscan/helpers.spec.js
vendored
4
js/src/3rdparty/etherscan/helpers.spec.js
vendored
@ -19,8 +19,8 @@ import { stringify } from 'qs';
|
|||||||
|
|
||||||
import { url } from './links';
|
import { url } from './links';
|
||||||
|
|
||||||
function mockget (requests, test) {
|
function mockget (requests, test, netVersion) {
|
||||||
let scope = nock(url(test));
|
let scope = nock(url(test, netVersion));
|
||||||
|
|
||||||
requests.forEach((request) => {
|
requests.forEach((request) => {
|
||||||
scope = scope
|
scope = scope
|
||||||
|
33
js/src/3rdparty/etherscan/links.js
vendored
33
js/src/3rdparty/etherscan/links.js
vendored
@ -14,14 +14,35 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
export const url = (isTestnet = false) => {
|
// NOTE: Keep 'isTestnet' for backwards library compatibility
|
||||||
return `https://${isTestnet ? 'testnet.' : ''}etherscan.io`;
|
export const url = (isTestnet = false, netVersion = '0') => {
|
||||||
|
let prefix = '';
|
||||||
|
|
||||||
|
switch (netVersion) {
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
prefix = 'testnet.';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '42':
|
||||||
|
prefix = 'kovan.';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '0':
|
||||||
|
default:
|
||||||
|
if (isTestnet) {
|
||||||
|
prefix = 'testnet.';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `https://${prefix}etherscan.io`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const txLink = (hash, isTestnet = false) => {
|
export const txLink = (hash, isTestnet = false, netVersion = '0') => {
|
||||||
return `${url(isTestnet)}/tx/${hash}`;
|
return `${url(isTestnet, netVersion)}/tx/${hash}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addressLink = (address, isTestnet = false) => {
|
export const addressLink = (address, isTestnet = false, netVersion = '0') => {
|
||||||
return `${url(isTestnet)}/address/${address}`;
|
return `${url(isTestnet, netVersion)}/address/${address}`;
|
||||||
};
|
};
|
||||||
|
13
js/src/3rdparty/sms-verification/index.js
vendored
13
js/src/3rdparty/sms-verification/index.js
vendored
@ -16,6 +16,19 @@
|
|||||||
|
|
||||||
import { stringify } from 'querystring';
|
import { stringify } from 'querystring';
|
||||||
|
|
||||||
|
export const isServerRunning = (isTestnet = false) => {
|
||||||
|
const port = isTestnet ? 8443 : 443;
|
||||||
|
return fetch(`https://sms-verification.parity.io:${port}/health`, {
|
||||||
|
mode: 'cors', cache: 'no-store'
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
return res.ok;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const postToServer = (query, isTestnet = false) => {
|
export const postToServer = (query, isTestnet = false) => {
|
||||||
const port = isTestnet ? 8443 : 443;
|
const port = isTestnet ? 8443 : 443;
|
||||||
query = stringify(query);
|
query = stringify(query);
|
||||||
|
@ -23,12 +23,12 @@ import { eventSignature } from '../../util/signature';
|
|||||||
|
|
||||||
export default class Event {
|
export default class Event {
|
||||||
constructor (abi) {
|
constructor (abi) {
|
||||||
this._name = abi.name;
|
|
||||||
this._inputs = EventParam.toEventParams(abi.inputs || []);
|
this._inputs = EventParam.toEventParams(abi.inputs || []);
|
||||||
this._anonymous = !!abi.anonymous;
|
this._anonymous = !!abi.anonymous;
|
||||||
|
|
||||||
const { id, signature } = eventSignature(this._name, this.inputParamTypes());
|
const { id, name, signature } = eventSignature(abi.name, this.inputParamTypes());
|
||||||
this._id = id;
|
this._id = id;
|
||||||
|
this._name = name;
|
||||||
this._signature = signature;
|
this._signature = signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,14 +22,14 @@ import { methodSignature } from '../util/signature';
|
|||||||
export default class Func {
|
export default class Func {
|
||||||
constructor (abi) {
|
constructor (abi) {
|
||||||
this._abi = abi;
|
this._abi = abi;
|
||||||
this._name = abi.name;
|
|
||||||
this._constant = !!abi.constant;
|
this._constant = !!abi.constant;
|
||||||
this._payable = abi.payable;
|
this._payable = abi.payable;
|
||||||
this._inputs = Param.toParams(abi.inputs || []);
|
this._inputs = Param.toParams(abi.inputs || []);
|
||||||
this._outputs = Param.toParams(abi.outputs || []);
|
this._outputs = Param.toParams(abi.outputs || []);
|
||||||
|
|
||||||
const { id, signature } = methodSignature(this._name, this.inputParamTypes());
|
const { id, name, signature } = methodSignature(abi.name, this.inputParamTypes());
|
||||||
this._id = id;
|
this._id = id;
|
||||||
|
this._name = name;
|
||||||
this._signature = signature;
|
this._signature = signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,18 @@ describe('abi/spec/Function', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('constructor', () => {
|
describe('constructor', () => {
|
||||||
|
it('returns signature correctly if name already contains it', () => {
|
||||||
|
const func = new Func({
|
||||||
|
name: 'test(bool,string)',
|
||||||
|
inputs: inputsArr,
|
||||||
|
outputs: outputsArr
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(func.name).to.equal('test');
|
||||||
|
expect(func.id).to.equal('test(bool,string)');
|
||||||
|
expect(func.signature).to.equal('02356205');
|
||||||
|
});
|
||||||
|
|
||||||
it('stores the parameters as received', () => {
|
it('stores the parameters as received', () => {
|
||||||
expect(func.name).to.equal('test');
|
expect(func.name).to.equal('test');
|
||||||
expect(func.constant).to.be.false;
|
expect(func.constant).to.be.false;
|
||||||
|
@ -17,15 +17,32 @@
|
|||||||
import { keccak_256 } from 'js-sha3'; // eslint-disable-line camelcase
|
import { keccak_256 } from 'js-sha3'; // eslint-disable-line camelcase
|
||||||
import { fromParamType } from '../spec/paramType/format';
|
import { fromParamType } from '../spec/paramType/format';
|
||||||
|
|
||||||
export function eventSignature (name, params) {
|
export function eventSignature (eventName, params) {
|
||||||
|
const { strName, name } = parseName(eventName);
|
||||||
const types = (params || []).map(fromParamType).join(',');
|
const types = (params || []).map(fromParamType).join(',');
|
||||||
const id = `${name || ''}(${types})`;
|
const id = `${strName}(${types})`;
|
||||||
|
const signature = strName ? keccak_256(id) : '';
|
||||||
|
|
||||||
return { id, signature: keccak_256(id) };
|
return { id, name, signature };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function methodSignature (name, params) {
|
export function methodSignature (methodName, params) {
|
||||||
const { id, signature } = eventSignature(name, params);
|
const { id, name, signature } = eventSignature(methodName, params);
|
||||||
|
|
||||||
return { id, signature: signature.substr(0, 8) };
|
return { id, name, signature: signature.substr(0, 8) };
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseName (name) {
|
||||||
|
const strName = `${name || ''}`;
|
||||||
|
const idx = strName.indexOf('(');
|
||||||
|
|
||||||
|
if (idx === -1) {
|
||||||
|
return { strName, name };
|
||||||
|
}
|
||||||
|
|
||||||
|
const trimmedName = strName.slice(0, idx);
|
||||||
|
return {
|
||||||
|
strName: trimmedName,
|
||||||
|
name: trimmedName
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -19,50 +19,93 @@ import { eventSignature, methodSignature } from './signature';
|
|||||||
describe('abi/util/signature', () => {
|
describe('abi/util/signature', () => {
|
||||||
describe('eventSignature', () => {
|
describe('eventSignature', () => {
|
||||||
it('encodes signature baz() correctly', () => {
|
it('encodes signature baz() correctly', () => {
|
||||||
expect(eventSignature('baz', []))
|
expect(eventSignature('baz', [])).to.deep.equal({
|
||||||
.to.deep.equal({ id: 'baz()', signature: 'a7916fac4f538170f7cd12c148552e2cba9fcd72329a2dd5b07a6fa906488ddf' });
|
id: 'baz()',
|
||||||
|
name: 'baz',
|
||||||
|
signature: 'a7916fac4f538170f7cd12c148552e2cba9fcd72329a2dd5b07a6fa906488ddf'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('encodes signature baz(uint32) correctly', () => {
|
it('encodes signature baz(uint32) correctly', () => {
|
||||||
expect(eventSignature('baz', [{ type: 'uint', length: 32 }]))
|
expect(eventSignature('baz', [{ type: 'uint', length: 32 }])).to.deep.equal({
|
||||||
.to.deep.equal({ id: 'baz(uint32)', signature: '7d68785e8fc871be024b75964bd86d093511d4bc2dc7cf7bea32c48a0efaecb1' });
|
id: 'baz(uint32)',
|
||||||
|
name: 'baz',
|
||||||
|
signature: '7d68785e8fc871be024b75964bd86d093511d4bc2dc7cf7bea32c48a0efaecb1'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('encodes signature baz(uint32, bool) correctly', () => {
|
it('encodes signature baz(uint32, bool) correctly', () => {
|
||||||
expect(eventSignature('baz', [{ type: 'uint', length: 32 }, { type: 'bool' }]))
|
expect(eventSignature('baz', [{ type: 'uint', length: 32 }, { type: 'bool' }])).to.deep.equal({
|
||||||
.to.deep.equal({ id: 'baz(uint32,bool)', signature: 'cdcd77c0992ec5bbfc459984220f8c45084cc24d9b6efed1fae540db8de801d2' });
|
id: 'baz(uint32,bool)',
|
||||||
|
name: 'baz',
|
||||||
|
signature: 'cdcd77c0992ec5bbfc459984220f8c45084cc24d9b6efed1fae540db8de801d2'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('encodes no-name signature correctly as ()', () => {
|
it('encodes no-name signature correctly as ()', () => {
|
||||||
expect(eventSignature(undefined, []))
|
expect(eventSignature(undefined, [])).to.deep.equal({
|
||||||
.to.deep.equal({ id: '()', signature: '861731d50c3880a2ca1994d5ec287b94b2f4bd832a67d3e41c08177bdd5674fe' });
|
id: '()',
|
||||||
|
name: undefined,
|
||||||
|
signature: ''
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('encodes no-params signature correctly as ()', () => {
|
it('encodes no-params signature correctly as ()', () => {
|
||||||
expect(eventSignature(undefined, undefined))
|
expect(eventSignature(undefined, undefined)).to.deep.equal({
|
||||||
.to.deep.equal({ id: '()', signature: '861731d50c3880a2ca1994d5ec287b94b2f4bd832a67d3e41c08177bdd5674fe' });
|
id: '()',
|
||||||
|
name: undefined,
|
||||||
|
signature: ''
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('methodSignature', () => {
|
describe('methodSignature', () => {
|
||||||
it('encodes signature baz() correctly', () => {
|
it('encodes signature baz() correctly', () => {
|
||||||
expect(methodSignature('baz', [])).to.deep.equal({ id: 'baz()', signature: 'a7916fac' });
|
expect(methodSignature('baz', [])).to.deep.equal({
|
||||||
|
id: 'baz()',
|
||||||
|
name: 'baz',
|
||||||
|
signature: 'a7916fac'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('encodes signature baz(uint32) correctly', () => {
|
it('encodes signature baz(uint32) correctly', () => {
|
||||||
expect(methodSignature('baz', [{ type: 'uint', length: 32 }])).to.deep.equal({ id: 'baz(uint32)', signature: '7d68785e' });
|
expect(methodSignature('baz', [{ type: 'uint', length: 32 }])).to.deep.equal({
|
||||||
|
id: 'baz(uint32)',
|
||||||
|
name: 'baz',
|
||||||
|
signature: '7d68785e'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('encodes signature baz(uint32, bool) correctly', () => {
|
it('encodes signature baz(uint32, bool) correctly', () => {
|
||||||
expect(methodSignature('baz', [{ type: 'uint', length: 32 }, { type: 'bool' }])).to.deep.equal({ id: 'baz(uint32,bool)', signature: 'cdcd77c0' });
|
expect(methodSignature('baz', [{ type: 'uint', length: 32 }, { type: 'bool' }])).to.deep.equal({
|
||||||
|
id: 'baz(uint32,bool)',
|
||||||
|
name: 'baz',
|
||||||
|
signature: 'cdcd77c0'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('encodes signature in name correctly', () => {
|
||||||
|
expect(methodSignature('baz(uint32,bool)', [{ type: 'uint', length: 32 }, { type: 'bool' }])).to.deep.equal({
|
||||||
|
id: 'baz(uint32,bool)',
|
||||||
|
name: 'baz',
|
||||||
|
signature: 'cdcd77c0'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('encodes no-name signature correctly as ()', () => {
|
it('encodes no-name signature correctly as ()', () => {
|
||||||
expect(methodSignature(undefined, [])).to.deep.equal({ id: '()', signature: '861731d5' });
|
expect(methodSignature(undefined, [])).to.deep.equal({
|
||||||
|
id: '()',
|
||||||
|
name: undefined,
|
||||||
|
signature: ''
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('encodes no-params signature correctly as ()', () => {
|
it('encodes no-params signature correctly as ()', () => {
|
||||||
expect(methodSignature(undefined, undefined)).to.deep.equal({ id: '()', signature: '861731d5' });
|
expect(methodSignature(undefined, undefined)).to.deep.equal({
|
||||||
|
id: '()',
|
||||||
|
name: undefined,
|
||||||
|
signature: ''
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import EventEmitter from 'eventemitter3';
|
||||||
|
|
||||||
import { Http, Ws } from './transport';
|
import { Http, Ws } from './transport';
|
||||||
import Contract from './contract';
|
import Contract from './contract';
|
||||||
|
|
||||||
@ -22,8 +24,10 @@ import Subscriptions from './subscriptions';
|
|||||||
import util from './util';
|
import util from './util';
|
||||||
import { isFunction } from './util/types';
|
import { isFunction } from './util/types';
|
||||||
|
|
||||||
export default class Api {
|
export default class Api extends EventEmitter {
|
||||||
constructor (transport) {
|
constructor (transport) {
|
||||||
|
super();
|
||||||
|
|
||||||
if (!transport || !isFunction(transport.execute)) {
|
if (!transport || !isFunction(transport.execute)) {
|
||||||
throw new Error('EthApi needs transport with execute() function defined');
|
throw new Error('EthApi needs transport with execute() function defined');
|
||||||
}
|
}
|
||||||
|
@ -248,18 +248,32 @@ export default class Contract {
|
|||||||
.call(callParams)
|
.call(callParams)
|
||||||
.then((encoded) => func.decodeOutput(encoded))
|
.then((encoded) => func.decodeOutput(encoded))
|
||||||
.then((tokens) => tokens.map((token) => token.value))
|
.then((tokens) => tokens.map((token) => token.value))
|
||||||
.then((returns) => returns.length === 1 ? returns[0] : returns);
|
.then((returns) => returns.length === 1 ? returns[0] : returns)
|
||||||
|
.catch((error) => {
|
||||||
|
console.warn(`${func.name}.call`, values, error);
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!func.constant) {
|
if (!func.constant) {
|
||||||
func.postTransaction = (options, values = []) => {
|
func.postTransaction = (options, values = []) => {
|
||||||
const _options = this._encodeOptions(func, this._addOptionsTo(options), values);
|
const _options = this._encodeOptions(func, this._addOptionsTo(options), values);
|
||||||
return this._api.parity.postTransaction(_options);
|
return this._api.parity
|
||||||
|
.postTransaction(_options)
|
||||||
|
.catch((error) => {
|
||||||
|
console.warn(`${func.name}.postTransaction`, values, error);
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
func.estimateGas = (options, values = []) => {
|
func.estimateGas = (options, values = []) => {
|
||||||
const _options = this._encodeOptions(func, this._addOptionsTo(options), values);
|
const _options = this._encodeOptions(func, this._addOptionsTo(options), values);
|
||||||
return this._api.eth.estimateGas(_options);
|
return this._api.eth
|
||||||
|
.estimateGas(_options)
|
||||||
|
.catch((error) => {
|
||||||
|
console.warn(`${func.name}.estimateGas`, values, error);
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,6 +399,10 @@ export default class Contract {
|
|||||||
this._subscribeToChanges();
|
this._subscribeToChanges();
|
||||||
return subscriptionId;
|
return subscriptionId;
|
||||||
});
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.warn('subscribe', event, _options, error);
|
||||||
|
throw error;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,6 +127,18 @@ export function inNumber16 (number) {
|
|||||||
return inHex(bn.toString(16));
|
return inHex(bn.toString(16));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function inOptionsCondition (condition) {
|
||||||
|
if (condition) {
|
||||||
|
if (condition.block) {
|
||||||
|
condition.block = condition.block ? inNumber10(condition.block) : null;
|
||||||
|
} else if (condition.time) {
|
||||||
|
condition.time = inNumber10(Math.floor(condition.time.getTime() / 1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
|
|
||||||
export function inOptions (options) {
|
export function inOptions (options) {
|
||||||
if (options) {
|
if (options) {
|
||||||
Object.keys(options).forEach((key) => {
|
Object.keys(options).forEach((key) => {
|
||||||
@ -136,6 +148,10 @@ export function inOptions (options) {
|
|||||||
options[key] = inAddress(options[key]);
|
options[key] = inAddress(options[key]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'condition':
|
||||||
|
options[key] = inOptionsCondition(options[key]);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'gas':
|
case 'gas':
|
||||||
case 'gasPrice':
|
case 'gasPrice':
|
||||||
options[key] = inNumber16((new BigNumber(options[key])).round());
|
options[key] = inNumber16((new BigNumber(options[key])).round());
|
||||||
|
@ -129,12 +129,31 @@ export function outNumber (number) {
|
|||||||
return new BigNumber(number || 0);
|
return new BigNumber(number || 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function outPeer (peer) {
|
||||||
|
const protocols = Object.keys(peer.protocols)
|
||||||
|
.reduce((obj, key) => {
|
||||||
|
if (peer.protocols[key]) {
|
||||||
|
obj[key] = {
|
||||||
|
...peer.protocols[key],
|
||||||
|
difficulty: outNumber(peer.protocols[key].difficulty)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
return {
|
||||||
|
...peer,
|
||||||
|
protocols
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function outPeers (peers) {
|
export function outPeers (peers) {
|
||||||
return {
|
return {
|
||||||
active: outNumber(peers.active),
|
active: outNumber(peers.active),
|
||||||
connected: outNumber(peers.connected),
|
connected: outNumber(peers.connected),
|
||||||
max: outNumber(peers.max),
|
max: outNumber(peers.max),
|
||||||
peers: peers.peers.map(p => { Object.keys(p.protocols).forEach(k => { p.protocols[k].difficulty = outNumber(p.protocols[k].difficulty); }); return p; })
|
peers: peers.peers.map((peer) => outPeer(peer))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,6 +219,18 @@ export function outSyncing (syncing) {
|
|||||||
return syncing;
|
return syncing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function outTransactionCondition (condition) {
|
||||||
|
if (condition) {
|
||||||
|
if (condition.block) {
|
||||||
|
condition.block = outNumber(condition.block);
|
||||||
|
} else if (condition.time) {
|
||||||
|
condition.time = outDate(condition.time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
|
|
||||||
export function outTransaction (tx) {
|
export function outTransaction (tx) {
|
||||||
if (tx) {
|
if (tx) {
|
||||||
Object.keys(tx).forEach((key) => {
|
Object.keys(tx).forEach((key) => {
|
||||||
@ -213,8 +244,14 @@ export function outTransaction (tx) {
|
|||||||
tx[key] = outNumber(tx[key]);
|
tx[key] = outNumber(tx[key]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'condition':
|
||||||
|
tx[key] = outTransactionCondition(tx[key]);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'minBlock':
|
case 'minBlock':
|
||||||
tx[key] = tx[key] ? outNumber(tx[key]) : null;
|
tx[key] = tx[key]
|
||||||
|
? outNumber(tx[key])
|
||||||
|
: null;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'creates':
|
case 'creates':
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
|
|
||||||
import { outBlock, outAccountInfo, outAddress, outChainStatus, outDate, outHistogram, outNumber, outPeers, outReceipt, outSyncing, outTransaction, outTrace } from './output';
|
import { outBlock, outAccountInfo, outAddress, outChainStatus, outDate, outHistogram, outNumber, outPeer, outPeers, outReceipt, outSyncing, outTransaction, outTrace } from './output';
|
||||||
import { isAddress, isBigNumber, isInstanceOf } from '../../../test/types';
|
import { isAddress, isBigNumber, isInstanceOf } from '../../../test/types';
|
||||||
|
|
||||||
describe('api/format/output', () => {
|
describe('api/format/output', () => {
|
||||||
@ -165,6 +165,66 @@ describe('api/format/output', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('outPeer', () => {
|
||||||
|
it('converts all internal numbers to BigNumbers', () => {
|
||||||
|
expect(outPeer({
|
||||||
|
caps: ['par/1'],
|
||||||
|
id: '0x01',
|
||||||
|
name: 'Parity',
|
||||||
|
network: {
|
||||||
|
localAddress: '10.0.0.1',
|
||||||
|
remoteAddress: '10.0.0.1'
|
||||||
|
},
|
||||||
|
protocols: {
|
||||||
|
par: {
|
||||||
|
difficulty: '0x0f',
|
||||||
|
head: '0x02',
|
||||||
|
version: 63
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})).to.deep.equal({
|
||||||
|
caps: ['par/1'],
|
||||||
|
id: '0x01',
|
||||||
|
name: 'Parity',
|
||||||
|
network: {
|
||||||
|
localAddress: '10.0.0.1',
|
||||||
|
remoteAddress: '10.0.0.1'
|
||||||
|
},
|
||||||
|
protocols: {
|
||||||
|
par: {
|
||||||
|
difficulty: new BigNumber(15),
|
||||||
|
head: '0x02',
|
||||||
|
version: 63
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not output null protocols', () => {
|
||||||
|
expect(outPeer({
|
||||||
|
caps: ['par/1'],
|
||||||
|
id: '0x01',
|
||||||
|
name: 'Parity',
|
||||||
|
network: {
|
||||||
|
localAddress: '10.0.0.1',
|
||||||
|
remoteAddress: '10.0.0.1'
|
||||||
|
},
|
||||||
|
protocols: {
|
||||||
|
les: null
|
||||||
|
}
|
||||||
|
})).to.deep.equal({
|
||||||
|
caps: ['par/1'],
|
||||||
|
id: '0x01',
|
||||||
|
name: 'Parity',
|
||||||
|
network: {
|
||||||
|
localAddress: '10.0.0.1',
|
||||||
|
remoteAddress: '10.0.0.1'
|
||||||
|
},
|
||||||
|
protocols: {}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('outPeers', () => {
|
describe('outPeers', () => {
|
||||||
it('converts all internal numbers to BigNumbers', () => {
|
it('converts all internal numbers to BigNumbers', () => {
|
||||||
expect(outPeers({
|
expect(outPeers({
|
||||||
@ -185,7 +245,8 @@ describe('api/format/output', () => {
|
|||||||
difficulty: '0x0f',
|
difficulty: '0x0f',
|
||||||
head: '0x02',
|
head: '0x02',
|
||||||
version: 63
|
version: 63
|
||||||
}
|
},
|
||||||
|
les: null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import { inAddress, inAddresses, inData, inHex, inNumber16, inOptions } from '../../format/input';
|
import { inAddress, inAddresses, inData, inHex, inNumber16, inOptions, inBlockNumber } from '../../format/input';
|
||||||
import { outAccountInfo, outAddress, outAddresses, outChainStatus, outHistogram, outNumber, outPeers, outTransaction } from '../../format/output';
|
import { outAccountInfo, outAddress, outAddresses, outChainStatus, outHistogram, outNumber, outPeers, outTransaction } from '../../format/output';
|
||||||
|
|
||||||
export default class Parity {
|
export default class Parity {
|
||||||
@ -76,6 +76,17 @@ export default class Parity {
|
|||||||
.execute('parity_dappsInterface');
|
.execute('parity_dappsInterface');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
decryptMessage (address, data) {
|
||||||
|
return this._transport
|
||||||
|
.execute('parity_decryptMessage', inAddress(address), inHex(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultAccount () {
|
||||||
|
return this._transport
|
||||||
|
.execute('parity_defaultAccount')
|
||||||
|
.then(outAddress);
|
||||||
|
}
|
||||||
|
|
||||||
defaultExtraData () {
|
defaultExtraData () {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('parity_defaultExtraData');
|
.execute('parity_defaultExtraData');
|
||||||
@ -101,6 +112,11 @@ export default class Parity {
|
|||||||
.execute('parity_enode');
|
.execute('parity_enode');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
encryptMessage (pubkey, data) {
|
||||||
|
return this._transport
|
||||||
|
.execute('parity_encryptMessage', inHex(pubkey), inHex(data));
|
||||||
|
}
|
||||||
|
|
||||||
executeUpgrade () {
|
executeUpgrade () {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('parity_executeUpgrade');
|
.execute('parity_executeUpgrade');
|
||||||
@ -111,6 +127,17 @@ export default class Parity {
|
|||||||
.execute('parity_extraData');
|
.execute('parity_extraData');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
futureTransactions () {
|
||||||
|
return this._transport
|
||||||
|
.execute('parity_futureTransactions');
|
||||||
|
}
|
||||||
|
|
||||||
|
gasCeilTarget () {
|
||||||
|
return this._transport
|
||||||
|
.execute('parity_gasCeilTarget')
|
||||||
|
.then(outNumber);
|
||||||
|
}
|
||||||
|
|
||||||
gasFloorTarget () {
|
gasFloorTarget () {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('parity_gasFloorTarget')
|
.execute('parity_gasFloorTarget')
|
||||||
@ -147,7 +174,7 @@ export default class Parity {
|
|||||||
|
|
||||||
importGethAccounts (accounts) {
|
importGethAccounts (accounts) {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('parity_importGethAccounts', inAddresses)
|
.execute('parity_importGethAccounts', inAddresses(accounts))
|
||||||
.then(outAddresses);
|
.then(outAddresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,11 +183,22 @@ export default class Parity {
|
|||||||
.execute('parity_killAccount', inAddress(account), password);
|
.execute('parity_killAccount', inAddress(account), password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listAccounts (count, offset = null, blockNumber = 'latest') {
|
||||||
|
return this._transport
|
||||||
|
.execute('parity_listAccounts', count, inAddress(offset), inBlockNumber(blockNumber))
|
||||||
|
.then((accounts) => (accounts || []).map(outAddress));
|
||||||
|
}
|
||||||
|
|
||||||
listRecentDapps () {
|
listRecentDapps () {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('parity_listRecentDapps');
|
.execute('parity_listRecentDapps');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listStorageKeys (address, count, hash = null, blockNumber = 'latest') {
|
||||||
|
return this._transport
|
||||||
|
.execute('parity_listStorageKeys', inAddress(address), count, inHex(hash), inBlockNumber(blockNumber));
|
||||||
|
}
|
||||||
|
|
||||||
removeAddress (address) {
|
removeAddress (address) {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('parity_removeAddress', inAddress(address));
|
.execute('parity_removeAddress', inAddress(address));
|
||||||
@ -265,6 +303,11 @@ export default class Parity {
|
|||||||
.then(outAddress);
|
.then(outAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
postSign (from, message) {
|
||||||
|
return this._transport
|
||||||
|
.execute('parity_postSign', inAddress(from), inHex(message));
|
||||||
|
}
|
||||||
|
|
||||||
postTransaction (options) {
|
postTransaction (options) {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('parity_postTransaction', inOptions(options));
|
.execute('parity_postTransaction', inOptions(options));
|
||||||
@ -311,16 +354,31 @@ export default class Parity {
|
|||||||
.execute('parity_setDappsAddresses', dappId, inAddresses(addresses));
|
.execute('parity_setDappsAddresses', dappId, inAddresses(addresses));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setEngineSigner (address, password) {
|
||||||
|
return this._transport
|
||||||
|
.execute('parity_setEngineSigner', inAddress(address), password);
|
||||||
|
}
|
||||||
|
|
||||||
setExtraData (data) {
|
setExtraData (data) {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('parity_setExtraData', inData(data));
|
.execute('parity_setExtraData', inData(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setGasCeilTarget (quantity) {
|
||||||
|
return this._transport
|
||||||
|
.execute('parity_setGasCeilTarget', inNumber16(quantity));
|
||||||
|
}
|
||||||
|
|
||||||
setGasFloorTarget (quantity) {
|
setGasFloorTarget (quantity) {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('parity_setGasFloorTarget', inNumber16(quantity));
|
.execute('parity_setGasFloorTarget', inNumber16(quantity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setMaxTransactionGas (quantity) {
|
||||||
|
return this._transport
|
||||||
|
.execute('parity_setMaxTransactionGas', inNumber16(quantity));
|
||||||
|
}
|
||||||
|
|
||||||
setMinGasPrice (quantity) {
|
setMinGasPrice (quantity) {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('parity_setMinGasPrice', inNumber16(quantity));
|
.execute('parity_setMinGasPrice', inNumber16(quantity));
|
||||||
|
@ -34,9 +34,9 @@ export default class Personal {
|
|||||||
.then(outAddress);
|
.then(outAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
signAndSendTransaction (options, password) {
|
sendTransaction (options, password) {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('personal_signAndSendTransaction', inOptions(options), password);
|
.execute('personal_sendTransaction', inOptions(options), password);
|
||||||
}
|
}
|
||||||
|
|
||||||
unlockAccount (account, password, duration = 1) {
|
unlockAccount (account, password, duration = 1) {
|
||||||
|
@ -23,6 +23,7 @@ export default class Eth {
|
|||||||
this._started = false;
|
this._started = false;
|
||||||
|
|
||||||
this._lastBlock = new BigNumber(-1);
|
this._lastBlock = new BigNumber(-1);
|
||||||
|
this._pollTimerId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isStarted () {
|
get isStarted () {
|
||||||
@ -37,7 +38,7 @@ export default class Eth {
|
|||||||
|
|
||||||
_blockNumber = () => {
|
_blockNumber = () => {
|
||||||
const nextTimeout = (timeout = 1000) => {
|
const nextTimeout = (timeout = 1000) => {
|
||||||
setTimeout(() => {
|
this._pollTimerId = setTimeout(() => {
|
||||||
this._blockNumber();
|
this._blockNumber();
|
||||||
}, timeout);
|
}, timeout);
|
||||||
};
|
};
|
||||||
@ -57,6 +58,6 @@ export default class Eth {
|
|||||||
|
|
||||||
nextTimeout();
|
nextTimeout();
|
||||||
})
|
})
|
||||||
.catch(nextTimeout);
|
.catch(() => nextTimeout());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ const events = {
|
|||||||
'logging': { module: 'logging' },
|
'logging': { module: 'logging' },
|
||||||
'eth_blockNumber': { module: 'eth' },
|
'eth_blockNumber': { module: 'eth' },
|
||||||
'parity_allAccountsInfo': { module: 'personal' },
|
'parity_allAccountsInfo': { module: 'personal' },
|
||||||
|
'parity_defaultAccount': { module: 'personal' },
|
||||||
'eth_accounts': { module: 'personal' },
|
'eth_accounts': { module: 'personal' },
|
||||||
'signer_requestsToConfirm': { module: 'signer' }
|
'signer_requestsToConfirm': { module: 'signer' }
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
@ -20,6 +20,9 @@ export default class Personal {
|
|||||||
this._api = api;
|
this._api = api;
|
||||||
this._updateSubscriptions = updateSubscriptions;
|
this._updateSubscriptions = updateSubscriptions;
|
||||||
this._started = false;
|
this._started = false;
|
||||||
|
|
||||||
|
this._lastDefaultAccount = '0x0';
|
||||||
|
this._pollTimerId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isStarted () {
|
get isStarted () {
|
||||||
@ -30,12 +33,44 @@ export default class Personal {
|
|||||||
this._started = true;
|
this._started = true;
|
||||||
|
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
|
this._defaultAccount(),
|
||||||
this._listAccounts(),
|
this._listAccounts(),
|
||||||
this._accountsInfo(),
|
this._accountsInfo(),
|
||||||
this._loggingSubscribe()
|
this._loggingSubscribe()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Because of the different API instances, the "wait for valid changes" approach
|
||||||
|
// doesn't work. Since the defaultAccount is critical to operation, we poll in exactly
|
||||||
|
// same way we do in ../eth (ala same as eth_blockNumber) and update. This should be moved
|
||||||
|
// to pub-sub as it becomes available
|
||||||
|
_defaultAccount = (timerDisabled = false) => {
|
||||||
|
const nextTimeout = (timeout = 1000) => {
|
||||||
|
if (!timerDisabled) {
|
||||||
|
this._pollTimerId = setTimeout(() => {
|
||||||
|
this._defaultAccount();
|
||||||
|
}, timeout);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!this._api.transport.isConnected) {
|
||||||
|
nextTimeout(500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._api.parity
|
||||||
|
.defaultAccount()
|
||||||
|
.then((defaultAccount) => {
|
||||||
|
if (this._lastDefaultAccount !== defaultAccount) {
|
||||||
|
this._lastDefaultAccount = defaultAccount;
|
||||||
|
this._updateSubscriptions('parity_defaultAccount', null, defaultAccount);
|
||||||
|
}
|
||||||
|
|
||||||
|
nextTimeout();
|
||||||
|
})
|
||||||
|
.catch(() => nextTimeout());
|
||||||
|
}
|
||||||
|
|
||||||
_listAccounts = () => {
|
_listAccounts = () => {
|
||||||
return this._api.eth
|
return this._api.eth
|
||||||
.accounts()
|
.accounts()
|
||||||
@ -46,9 +81,19 @@ export default class Personal {
|
|||||||
|
|
||||||
_accountsInfo = () => {
|
_accountsInfo = () => {
|
||||||
return this._api.parity
|
return this._api.parity
|
||||||
.allAccountsInfo()
|
.accountsInfo()
|
||||||
.then((info) => {
|
.then((info) => {
|
||||||
this._updateSubscriptions('parity_allAccountsInfo', null, info);
|
this._updateSubscriptions('parity_accountsInfo', null, info);
|
||||||
|
|
||||||
|
return this._api.parity
|
||||||
|
.allAccountsInfo()
|
||||||
|
.catch(() => {
|
||||||
|
// NOTE: This fails on non-secure APIs, swallow error
|
||||||
|
return {};
|
||||||
|
})
|
||||||
|
.then((allInfo) => {
|
||||||
|
this._updateSubscriptions('parity_allAccountsInfo', null, allInfo);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,6 +118,11 @@ export default class Personal {
|
|||||||
case 'parity_setAccountMeta':
|
case 'parity_setAccountMeta':
|
||||||
this._accountsInfo();
|
this._accountsInfo();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case 'parity_setDappsAddresses':
|
||||||
|
case 'parity_setNewDappsWhitelist':
|
||||||
|
this._defaultAccount(true);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
@ -18,31 +18,51 @@ import sinon from 'sinon';
|
|||||||
|
|
||||||
import Personal from './personal';
|
import Personal from './personal';
|
||||||
|
|
||||||
|
const TEST_DEFAULT = '0xfa64203C044691aA57251aF95f4b48d85eC00Dd5';
|
||||||
const TEST_INFO = {
|
const TEST_INFO = {
|
||||||
'0xfa64203C044691aA57251aF95f4b48d85eC00Dd5': {
|
[TEST_DEFAULT]: {
|
||||||
name: 'test'
|
name: 'test'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const TEST_LIST = ['0xfa64203C044691aA57251aF95f4b48d85eC00Dd5'];
|
const TEST_LIST = [TEST_DEFAULT];
|
||||||
|
|
||||||
function stubApi (accounts, info) {
|
function stubApi (accounts, info) {
|
||||||
const _calls = {
|
const _calls = {
|
||||||
|
accountsInfo: [],
|
||||||
allAccountsInfo: [],
|
allAccountsInfo: [],
|
||||||
listAccounts: []
|
listAccounts: [],
|
||||||
|
defaultAccount: []
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_calls,
|
_calls,
|
||||||
|
transport: {
|
||||||
|
isConnected: true
|
||||||
|
},
|
||||||
parity: {
|
parity: {
|
||||||
|
accountsInfo: () => {
|
||||||
|
const stub = sinon.stub().resolves(info || TEST_INFO)();
|
||||||
|
|
||||||
|
_calls.accountsInfo.push(stub);
|
||||||
|
return stub;
|
||||||
|
},
|
||||||
allAccountsInfo: () => {
|
allAccountsInfo: () => {
|
||||||
const stub = sinon.stub().resolves(info || TEST_INFO)();
|
const stub = sinon.stub().resolves(info || TEST_INFO)();
|
||||||
|
|
||||||
_calls.allAccountsInfo.push(stub);
|
_calls.allAccountsInfo.push(stub);
|
||||||
return stub;
|
return stub;
|
||||||
|
},
|
||||||
|
defaultAccount: () => {
|
||||||
|
const stub = sinon.stub().resolves(Object.keys(info || TEST_INFO)[0])();
|
||||||
|
|
||||||
|
_calls.defaultAccount.push(stub);
|
||||||
|
return stub;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
eth: {
|
eth: {
|
||||||
accounts: () => {
|
accounts: () => {
|
||||||
const stub = sinon.stub().resolves(accounts || TEST_LIST)();
|
const stub = sinon.stub().resolves(accounts || TEST_LIST)();
|
||||||
|
|
||||||
_calls.listAccounts.push(stub);
|
_calls.listAccounts.push(stub);
|
||||||
return stub;
|
return stub;
|
||||||
}
|
}
|
||||||
@ -85,6 +105,10 @@ describe('api/subscriptions/personal', () => {
|
|||||||
expect(personal.isStarted).to.be.true;
|
expect(personal.isStarted).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('calls parity_accountsInfo', () => {
|
||||||
|
expect(api._calls.accountsInfo.length).to.be.ok;
|
||||||
|
});
|
||||||
|
|
||||||
it('calls parity_allAccountsInfo', () => {
|
it('calls parity_allAccountsInfo', () => {
|
||||||
expect(api._calls.allAccountsInfo.length).to.be.ok;
|
expect(api._calls.allAccountsInfo.length).to.be.ok;
|
||||||
});
|
});
|
||||||
@ -94,8 +118,10 @@ describe('api/subscriptions/personal', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('updates subscribers', () => {
|
it('updates subscribers', () => {
|
||||||
expect(cb.firstCall).to.have.been.calledWith('eth_accounts', null, TEST_LIST);
|
expect(cb).to.have.been.calledWith('parity_defaultAccount', null, TEST_DEFAULT);
|
||||||
expect(cb.secondCall).to.have.been.calledWith('parity_allAccountsInfo', null, TEST_INFO);
|
expect(cb).to.have.been.calledWith('eth_accounts', null, TEST_LIST);
|
||||||
|
expect(cb).to.have.been.calledWith('parity_accountsInfo', null, TEST_INFO);
|
||||||
|
expect(cb).to.have.been.calledWith('parity_allAccountsInfo', null, TEST_INFO);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -110,7 +136,15 @@ describe('api/subscriptions/personal', () => {
|
|||||||
expect(personal.isStarted).to.be.true;
|
expect(personal.isStarted).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('calls parity_defaultAccount', () => {
|
||||||
|
expect(api._calls.defaultAccount.length).to.be.ok;
|
||||||
|
});
|
||||||
|
|
||||||
it('calls personal_accountsInfo', () => {
|
it('calls personal_accountsInfo', () => {
|
||||||
|
expect(api._calls.accountsInfo.length).to.be.ok;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls personal_allAccountsInfo', () => {
|
||||||
expect(api._calls.allAccountsInfo.length).to.be.ok;
|
expect(api._calls.allAccountsInfo.length).to.be.ok;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user