Compare commits
77 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d44b008d92 | ||
|
|
b93e943fb7 | ||
|
|
c3f0ae018d | ||
|
|
9760ddc5b8 | ||
|
|
aa7dfdf0f5 | ||
|
|
1f176c7798 | ||
|
|
823f207d25 | ||
|
|
0ba6d83317 | ||
|
|
bd65d216e1 | ||
|
|
94f0f12077 | ||
|
|
1e45a9ec2e | ||
|
|
f7f092dbe7 | ||
|
|
b822a0d12d | ||
|
|
e99760de25 | ||
|
|
c39622952d | ||
|
|
b8b5a23b12 | ||
|
|
fb82c6c415 | ||
|
|
4a9bd0af64 | ||
|
|
d20475d9ad | ||
|
|
f1cd03bf1f | ||
|
|
e128418147 | ||
|
|
314e2764ae | ||
|
|
1aea9caf6d | ||
|
|
8dfc10ede9 | ||
|
|
4d9f13196f | ||
|
|
4b857bf4b0 | ||
|
|
0a5c6a9ac7 | ||
|
|
6cce5c8c9e | ||
|
|
ab065ecbd0 | ||
|
|
36015c960a | ||
|
|
8c4938d9c6 | ||
|
|
2f3cddeea8 | ||
|
|
8c6e3f314a | ||
|
|
96cbfba916 | ||
|
|
18b8d6aca6 | ||
|
|
6a44a0cf95 | ||
|
|
b7860e4a3f | ||
|
|
4a910a762d | ||
|
|
1626c78ae2 | ||
|
|
7f4e700013 | ||
|
|
987390fb7d | ||
|
|
797f23f30b | ||
|
|
c1da49bbc4 | ||
|
|
1164193019 | ||
|
|
1c217cbf2b | ||
|
|
d24f71f150 | ||
|
|
4c66a021ec | ||
|
|
ccc57328e2 | ||
|
|
77240b6e5a | ||
|
|
2e428ddd58 | ||
|
|
cd4081c149 | ||
|
|
428342d69d | ||
|
|
8ee9b262f9 | ||
|
|
e2bc251ff4 | ||
|
|
d15372c8a6 | ||
|
|
bcf2245110 | ||
|
|
36f74fdf0d | ||
|
|
45402544d3 | ||
|
|
ab236690df | ||
|
|
34e81101d7 | ||
|
|
07d4b9bbc9 | ||
|
|
d25a20b274 | ||
|
|
70d17ce1d8 | ||
|
|
3b14bcf29a | ||
|
|
4fc69e11d6 | ||
|
|
8e4df824b0 | ||
|
|
e1f2e840cb | ||
|
|
2a36a89c36 | ||
|
|
b643f4011d | ||
|
|
814304bdd7 | ||
|
|
f90607302d | ||
|
|
af826f877e | ||
|
|
f9a0aa0022 | ||
|
|
c4196a5de3 | ||
|
|
3b56e8eded | ||
|
|
b3ccbbe913 | ||
|
|
fe0f037f23 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -19,6 +19,9 @@
|
|||||||
# mac stuff
|
# mac stuff
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
# npm stuff
|
||||||
|
npm-debug.log
|
||||||
|
|
||||||
# gdb files
|
# gdb files
|
||||||
.gdb_history
|
.gdb_history
|
||||||
|
|
||||||
|
|||||||
130
.gitlab-ci.yml
130
.gitlab-ci.yml
@@ -1,8 +1,8 @@
|
|||||||
stages:
|
stages:
|
||||||
- test
|
- test
|
||||||
- js-build
|
- js-build
|
||||||
- build
|
|
||||||
- push-release
|
- push-release
|
||||||
|
- build
|
||||||
variables:
|
variables:
|
||||||
GIT_DEPTH: "3"
|
GIT_DEPTH: "3"
|
||||||
SIMPLECOV: "true"
|
SIMPLECOV: "true"
|
||||||
@@ -14,7 +14,7 @@ cache:
|
|||||||
untracked: true
|
untracked: true
|
||||||
linux-stable:
|
linux-stable:
|
||||||
stage: build
|
stage: build
|
||||||
image: ethcore/rust:stable
|
image: parity/rust:gitlab-ci
|
||||||
only:
|
only:
|
||||||
- beta
|
- beta
|
||||||
- tags
|
- tags
|
||||||
@@ -26,14 +26,14 @@ linux-stable:
|
|||||||
- cargo build -j $(nproc) --release -p ethstore
|
- cargo build -j $(nproc) --release -p ethstore
|
||||||
- cargo build -j $(nproc) --release -p ethkey
|
- cargo build -j $(nproc) --release -p ethkey
|
||||||
- strip target/release/parity
|
- strip target/release/parity
|
||||||
- strip target/release/evm
|
- strip target/release/parity-evm
|
||||||
- strip target/release/ethstore
|
- strip target/release/ethstore
|
||||||
- strip target/release/ethkey
|
- strip target/release/ethkey
|
||||||
- export SHA3=$(target/release/parity tools hash target/release/parity)
|
- export SHA3=$(target/release/parity tools hash target/release/parity)
|
||||||
- md5sum target/release/parity > parity.md5
|
- md5sum target/release/parity > parity.md5
|
||||||
- sh scripts/deb-build.sh amd64
|
- sh scripts/deb-build.sh amd64
|
||||||
- cp target/release/parity deb/usr/bin/parity
|
- cp target/release/parity deb/usr/bin/parity
|
||||||
- cp target/release/evm deb/usr/bin/evm
|
- cp target/release/parity-evm deb/usr/bin/parity-evm
|
||||||
- cp target/release/ethstore deb/usr/bin/ethstore
|
- cp target/release/ethstore deb/usr/bin/ethstore
|
||||||
- cp target/release/ethkey deb/usr/bin/ethkey
|
- cp target/release/ethkey deb/usr/bin/ethkey
|
||||||
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
|
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
|
||||||
@@ -41,7 +41,7 @@ linux-stable:
|
|||||||
- md5sum "parity_"$VER"_amd64.deb" > "parity_"$VER"_amd64.deb.md5"
|
- md5sum "parity_"$VER"_amd64.deb" > "parity_"$VER"_amd64.deb.md5"
|
||||||
- aws configure set aws_access_key_id $s3_key
|
- aws configure set aws_access_key_id $s3_key
|
||||||
- aws configure set aws_secret_access_key $s3_secret
|
- 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
|
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable|nightly)$ ]]; 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-linux-gnu
|
- aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu
|
||||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/parity --body target/release/parity
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/parity --body target/release/parity
|
||||||
- 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
|
||||||
@@ -55,13 +55,46 @@ linux-stable:
|
|||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- target/release/parity
|
- target/release/parity
|
||||||
- target/release/parity/evmbin
|
- target/release/parity-evm
|
||||||
- target/release/parity/ethstore
|
- target/release/ethstore
|
||||||
- target/release/parity/ethkey
|
- target/release/ethkey
|
||||||
name: "stable-x86_64-unknown-linux-gnu_parity"
|
name: "stable-x86_64-unknown-linux-gnu_parity"
|
||||||
|
linux-snap:
|
||||||
|
stage: build
|
||||||
|
image: parity/snapcraft:gitlab-ci
|
||||||
|
only:
|
||||||
|
- snap
|
||||||
|
- beta
|
||||||
|
- stable
|
||||||
|
- tags
|
||||||
|
- triggers
|
||||||
|
script:
|
||||||
|
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
|
||||||
|
- cd snap
|
||||||
|
- rm -rf *snap
|
||||||
|
- sed -i 's/master/'"$VER"'/g' snapcraft.yaml
|
||||||
|
- echo "Version:"$VER
|
||||||
|
- snapcraft
|
||||||
|
- ls
|
||||||
|
#- cp "parity_"*"_amd64.snap" "parity_"$VER"_amd64.snap"
|
||||||
|
- md5sum "parity_"$VER"_amd64.snap" > "parity_"$VER"_amd64.snap.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|nightly)$ ]]; 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/x86_64-unknown-linux-gnu/"parity_"$VER"_amd64.snap" --body "parity_"$VER"_amd64.snap"
|
||||||
|
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/"parity_"$VER"_amd64.snap.md5" --body "parity_"$VER"_amd64.snap.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:1338/push-build/$CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu
|
||||||
|
tags:
|
||||||
|
- rust
|
||||||
|
- rust-stable
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- scripts/parity_*_amd64.snap
|
||||||
|
name: "stable-x86_64-unknown-snap-gnu_parity"
|
||||||
linux-stable-debian:
|
linux-stable-debian:
|
||||||
stage: build
|
stage: build
|
||||||
image: ethcore/rust-debian:latest
|
image: parity/rust-debian:gitlab-ci
|
||||||
only:
|
only:
|
||||||
- beta
|
- beta
|
||||||
- tags
|
- tags
|
||||||
@@ -73,14 +106,14 @@ linux-stable-debian:
|
|||||||
- cargo build -j $(nproc) --release -p ethstore
|
- cargo build -j $(nproc) --release -p ethstore
|
||||||
- cargo build -j $(nproc) --release -p ethkey
|
- cargo build -j $(nproc) --release -p ethkey
|
||||||
- strip target/release/parity
|
- strip target/release/parity
|
||||||
- strip target/release/evm
|
- strip target/release/parity-evm
|
||||||
- strip target/release/ethstore
|
- strip target/release/ethstore
|
||||||
- strip target/release/ethkey
|
- strip target/release/ethkey
|
||||||
- export SHA3=$(target/release/parity tools hash target/release/parity)
|
- export SHA3=$(target/release/parity tools hash target/release/parity)
|
||||||
- md5sum target/release/parity > parity.md5
|
- md5sum target/release/parity > parity.md5
|
||||||
- sh scripts/deb-build.sh amd64
|
- sh scripts/deb-build.sh amd64
|
||||||
- cp target/release/parity deb/usr/bin/parity
|
- cp target/release/parity deb/usr/bin/parity
|
||||||
- cp target/release/evm deb/usr/bin/evm
|
- cp target/release/parity-evm deb/usr/bin/parity-evm
|
||||||
- cp target/release/ethstore deb/usr/bin/ethstore
|
- cp target/release/ethstore deb/usr/bin/ethstore
|
||||||
- cp target/release/ethkey deb/usr/bin/ethkey
|
- cp target/release/ethkey deb/usr/bin/ethkey
|
||||||
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
|
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
|
||||||
@@ -88,7 +121,7 @@ linux-stable-debian:
|
|||||||
- md5sum "parity_"$VER"_amd64.deb" > "parity_"$VER"_amd64.deb.md5"
|
- md5sum "parity_"$VER"_amd64.deb" > "parity_"$VER"_amd64.deb.md5"
|
||||||
- aws configure set aws_access_key_id $s3_key
|
- aws configure set aws_access_key_id $s3_key
|
||||||
- aws configure set aws_secret_access_key $s3_secret
|
- 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
|
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable|nightly)$ ]]; 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 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 --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.md5 --body parity.md5
|
||||||
@@ -105,7 +138,7 @@ linux-stable-debian:
|
|||||||
name: "stable-x86_64-unknown-debian-gnu_parity"
|
name: "stable-x86_64-unknown-debian-gnu_parity"
|
||||||
linux-beta:
|
linux-beta:
|
||||||
stage: build
|
stage: build
|
||||||
image: ethcore/rust:beta
|
image: parity/rust:gitlab-ci
|
||||||
only:
|
only:
|
||||||
- beta
|
- beta
|
||||||
- tags
|
- tags
|
||||||
@@ -124,7 +157,7 @@ linux-beta:
|
|||||||
allow_failure: true
|
allow_failure: true
|
||||||
linux-nightly:
|
linux-nightly:
|
||||||
stage: build
|
stage: build
|
||||||
image: ethcore/rust:nightly
|
image: parity/rust:gitlab-ci
|
||||||
only:
|
only:
|
||||||
- beta
|
- beta
|
||||||
- tags
|
- tags
|
||||||
@@ -143,7 +176,7 @@ linux-nightly:
|
|||||||
allow_failure: true
|
allow_failure: true
|
||||||
linux-centos:
|
linux-centos:
|
||||||
stage: build
|
stage: build
|
||||||
image: ethcore/rust-centos:latest
|
image: parity/rust-centos:gitlab-ci
|
||||||
only:
|
only:
|
||||||
- beta
|
- beta
|
||||||
- tags
|
- tags
|
||||||
@@ -159,7 +192,7 @@ linux-centos:
|
|||||||
- export SHA3=$(target/release/parity tools hash target/release/parity)
|
- export SHA3=$(target/release/parity tools hash target/release/parity)
|
||||||
- aws configure set aws_access_key_id $s3_key
|
- aws configure set aws_access_key_id $s3_key
|
||||||
- aws configure set aws_secret_access_key $s3_secret
|
- 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
|
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable|nightly)$ ]]; 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-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
|
||||||
@@ -174,7 +207,7 @@ linux-centos:
|
|||||||
name: "x86_64-unknown-centos-gnu_parity"
|
name: "x86_64-unknown-centos-gnu_parity"
|
||||||
linux-i686:
|
linux-i686:
|
||||||
stage: build
|
stage: build
|
||||||
image: ethcore/rust-i686:latest
|
image: parity/rust-i686:gitlab-ci
|
||||||
only:
|
only:
|
||||||
- beta
|
- beta
|
||||||
- tags
|
- tags
|
||||||
@@ -196,7 +229,7 @@ linux-i686:
|
|||||||
- md5sum "parity_"$VER"_i386.deb" > "parity_"$VER"_i386.deb.md5"
|
- md5sum "parity_"$VER"_i386.deb" > "parity_"$VER"_i386.deb.md5"
|
||||||
- aws configure set aws_access_key_id $s3_key
|
- aws configure set aws_access_key_id $s3_key
|
||||||
- aws configure set aws_secret_access_key $s3_secret
|
- 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
|
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable|nightly)$ ]]; 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/$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
|
||||||
@@ -214,7 +247,7 @@ linux-i686:
|
|||||||
allow_failure: true
|
allow_failure: true
|
||||||
linux-armv7:
|
linux-armv7:
|
||||||
stage: build
|
stage: build
|
||||||
image: ethcore/rust-armv7:latest
|
image: parity/rust-armv7:gitlab-ci
|
||||||
only:
|
only:
|
||||||
- beta
|
- beta
|
||||||
- tags
|
- tags
|
||||||
@@ -242,7 +275,7 @@ linux-armv7:
|
|||||||
- md5sum "parity_"$VER"_armhf.deb" > "parity_"$VER"_armhf.deb.md5"
|
- md5sum "parity_"$VER"_armhf.deb" > "parity_"$VER"_armhf.deb.md5"
|
||||||
- aws configure set aws_access_key_id $s3_key
|
- aws configure set aws_access_key_id $s3_key
|
||||||
- aws configure set aws_secret_access_key $s3_secret
|
- 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
|
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable|nightly)$ ]]; 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/$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
|
||||||
@@ -260,7 +293,7 @@ linux-armv7:
|
|||||||
allow_failure: true
|
allow_failure: true
|
||||||
linux-arm:
|
linux-arm:
|
||||||
stage: build
|
stage: build
|
||||||
image: ethcore/rust-arm:latest
|
image: parity/rust-arm:gitlab-ci
|
||||||
only:
|
only:
|
||||||
- beta
|
- beta
|
||||||
- tags
|
- tags
|
||||||
@@ -288,7 +321,7 @@ linux-arm:
|
|||||||
- md5sum "parity_"$VER"_armhf.deb" > "parity_"$VER"_armhf.deb.md5"
|
- md5sum "parity_"$VER"_armhf.deb" > "parity_"$VER"_armhf.deb.md5"
|
||||||
- aws configure set aws_access_key_id $s3_key
|
- aws configure set aws_access_key_id $s3_key
|
||||||
- aws configure set aws_secret_access_key $s3_secret
|
- 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
|
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable|nightly)$ ]]; 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/$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
|
||||||
@@ -306,12 +339,12 @@ linux-arm:
|
|||||||
allow_failure: true
|
allow_failure: true
|
||||||
linux-armv6:
|
linux-armv6:
|
||||||
stage: build
|
stage: build
|
||||||
image: ethcore/rust-armv6:latest
|
image: parity/rust-armv6:gitlab-ci
|
||||||
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++
|
||||||
@@ -329,7 +362,7 @@ linux-armv6:
|
|||||||
- md5sum target/$PLATFORM/release/parity > parity.md5
|
- md5sum target/$PLATFORM/release/parity > parity.md5
|
||||||
- aws configure set aws_access_key_id $s3_key
|
- aws configure set aws_access_key_id $s3_key
|
||||||
- aws configure set aws_secret_access_key $s3_secret
|
- 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
|
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable|nightly)$ ]]; 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/$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
|
||||||
@@ -345,7 +378,7 @@ linux-armv6:
|
|||||||
allow_failure: true
|
allow_failure: true
|
||||||
linux-aarch64:
|
linux-aarch64:
|
||||||
stage: build
|
stage: build
|
||||||
image: ethcore/rust-aarch64:latest
|
image: parity/rust-arm64:gitlab-ci
|
||||||
only:
|
only:
|
||||||
- beta
|
- beta
|
||||||
- tags
|
- tags
|
||||||
@@ -373,7 +406,7 @@ linux-aarch64:
|
|||||||
- md5sum "parity_"$VER"_arm64.deb" > "parity_"$VER"_arm64.deb.md5"
|
- md5sum "parity_"$VER"_arm64.deb" > "parity_"$VER"_arm64.deb.md5"
|
||||||
- aws configure set aws_access_key_id $s3_key
|
- aws configure set aws_access_key_id $s3_key
|
||||||
- aws configure set aws_secret_access_key $s3_secret
|
- 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
|
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable|nightly)$ ]]; 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/$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.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"
|
||||||
@@ -409,16 +442,16 @@ darwin:
|
|||||||
packagesbuild -v mac/Parity.pkgproj
|
packagesbuild -v mac/Parity.pkgproj
|
||||||
productsign --sign 'Developer ID Installer: PARITY TECHNOLOGIES LIMITED (P2PX3JU8FT)' target/release/Parity\ Ethereum.pkg target/release/Parity\ Ethereum-signed.pkg
|
productsign --sign 'Developer ID Installer: PARITY TECHNOLOGIES LIMITED (P2PX3JU8FT)' target/release/Parity\ Ethereum.pkg target/release/Parity\ Ethereum-signed.pkg
|
||||||
export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
|
export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
|
||||||
mv target/release/Parity\ Ethereum-signed.pkg "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg"
|
mv target/release/Parity\ Ethereum-signed.pkg "parity-"$VER"-osx-installer.pkg"
|
||||||
md5sum "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg" >> "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg.md5"
|
md5sum "parity-"$VER"-osx-installer.pkg" >> "parity-"$VER"-osx-installer.pkg.md5"
|
||||||
aws configure set aws_access_key_id $s3_key
|
aws configure set aws_access_key_id $s3_key
|
||||||
aws configure set aws_secret_access_key $s3_secret
|
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
|
if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable|nightly)$ ]]; 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/$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/release/parity
|
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.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"-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-"$VER"-osx-installer.pkg" --body "parity-"$VER"-osx-installer.pkg"
|
||||||
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.pkg.md5" --body "parity-"$VER"-osx-installer.pkg.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:
|
||||||
@@ -460,17 +493,17 @@ windows:
|
|||||||
- zip win-installer.zip InstallParity.exe InstallParity.exe.md5
|
- zip win-installer.zip InstallParity.exe InstallParity.exe.md5
|
||||||
- md5sums win-installer.zip > win-installer.zip.md5
|
- md5sums win-installer.zip > win-installer.zip.md5
|
||||||
- cd ..\target\release\
|
- cd ..\target\release\
|
||||||
- md5sums parity.exe parity.pdb > parity.md5
|
|
||||||
- md5sums parity.exe > parity.exe.md5
|
- md5sums parity.exe > parity.exe.md5
|
||||||
- zip parity.zip parity.exe parity.pdb parity.md5
|
- zip parity.zip parity.exe parity.md5
|
||||||
- md5sums parity.zip > parity.zip.md5
|
- md5sums parity.zip > parity.zip.md5
|
||||||
- cd ..\..
|
- cd ..\..
|
||||||
- aws configure set aws_access_key_id %s3_key%
|
- aws configure set aws_access_key_id %s3_key%
|
||||||
- aws configure set aws_secret_access_key %s3_secret%
|
- aws configure set aws_secret_access_key %s3_secret%
|
||||||
- echo %CI_BUILD_REF_NAME%
|
- echo %CI_BUILD_REF_NAME%
|
||||||
- echo %CI_BUILD_REF_NAME% | findstr /R "master" >nul 2>&1 && set S3_BUCKET=builds-parity-published || set S3_BUCKET=builds-parity
|
- echo %CI_BUILD_REF_NAME% | findstr /R "master" >nul 2>&1 && set S3_BUCKET=builds-parity-published|| set S3_BUCKET=builds-parity
|
||||||
- echo %CI_BUILD_REF_NAME% | findstr /R "beta" >nul 2>&1 && set S3_BUCKET=builds-parity-published || set S3_BUCKET=builds-parity
|
- echo %CI_BUILD_REF_NAME% | findstr /R "beta" >nul 2>&1 && set S3_BUCKET=builds-parity-published|| set S3_BUCKET=builds-parity
|
||||||
- echo %CI_BUILD_REF_NAME% | findstr /R "stable" >nul 2>&1 && set S3_BUCKET=builds-parity-published || set S3_BUCKET=builds-parity
|
- echo %CI_BUILD_REF_NAME% | findstr /R "stable" >nul 2>&1 && set S3_BUCKET=builds-parity-published|| set S3_BUCKET=builds-parity
|
||||||
|
- echo %CI_BUILD_REF_NAME% | findstr /R "nightly" >nul 2>&1 && set S3_BUCKET=builds-parity-published|| set S3_BUCKET=builds-parity
|
||||||
- echo %S3_BUCKET%
|
- echo %S3_BUCKET%
|
||||||
- aws s3 rm --recursive s3://%S3_BUCKET%/%CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc
|
- aws s3 rm --recursive s3://%S3_BUCKET%/%CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc
|
||||||
- aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.exe --body target\release\parity.exe
|
- aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.exe --body target\release\parity.exe
|
||||||
@@ -488,7 +521,6 @@ windows:
|
|||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- target/release/parity.exe
|
- target/release/parity.exe
|
||||||
- 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:
|
docker-build:
|
||||||
@@ -502,6 +534,10 @@ docker-build:
|
|||||||
- if [ "$CI_BUILD_REF_NAME" == "beta-release" ]; then DOCKER_TAG="latest"; else DOCKER_TAG=$CI_BUILD_REF_NAME; fi
|
- 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
|
- docker login -u $Docker_Hub_User -p $Docker_Hub_Pass
|
||||||
- sh scripts/docker-build.sh $DOCKER_TAG
|
- sh scripts/docker-build.sh $DOCKER_TAG
|
||||||
|
- docker logout
|
||||||
|
- docker login -u $Docker_Hub_User_Parity -p $Docker_Hub_Pass_Parity
|
||||||
|
- sh scripts/docker-build.sh $DOCKER_TAG
|
||||||
|
- docker logout
|
||||||
tags:
|
tags:
|
||||||
- docker
|
- docker
|
||||||
test-darwin:
|
test-darwin:
|
||||||
@@ -531,19 +567,19 @@ test-windows:
|
|||||||
allow_failure: true
|
allow_failure: true
|
||||||
test-rust-stable:
|
test-rust-stable:
|
||||||
stage: test
|
stage: test
|
||||||
image: ethcore/rust:stable
|
image: parity/rust:gitlab-ci
|
||||||
before_script:
|
before_script:
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
- export RUST_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep -v -e ^js -e ^\\. -e ^LICENSE -e ^README.md -e ^appveyor.yml -e ^test.sh -e ^windows/ -e ^scripts/ -e^mac/ -e ^nsis/ | wc -l)
|
- export RUST_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep -v -e ^js -e ^\\. -e ^LICENSE -e ^README.md -e ^appveyor.yml -e ^test.sh -e ^windows/ -e ^scripts/ -e^mac/ -e ^nsis/ | wc -l)
|
||||||
script:
|
script:
|
||||||
- export RUST_BACKTRACE=1
|
- export RUST_BACKTRACE=1
|
||||||
- if [ $RUST_FILES_MODIFIED -eq 0 ]; then echo "Skipping Rust tests since no Rust files modified."; else ./test.sh $CARGOFLAGS&&./scripts/cov.sh "$KCOV_CMD"; fi
|
- if [ $RUST_FILES_MODIFIED -eq 0 ]; then echo "Skipping Rust tests since no Rust files modified."; else ./test.sh $CARGOFLAGS; fi
|
||||||
tags:
|
tags:
|
||||||
- rust
|
- rust
|
||||||
- rust-stable
|
- rust-stable
|
||||||
js-test:
|
js-test:
|
||||||
stage: test
|
stage: test
|
||||||
image: ethcore/rust:stable
|
image: parity/rust:gitlab-ci
|
||||||
before_script:
|
before_script:
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
- export JS_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep ^js/ | wc -l)
|
- export JS_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep ^js/ | wc -l)
|
||||||
@@ -557,11 +593,12 @@ test-rust-beta:
|
|||||||
stage: test
|
stage: test
|
||||||
only:
|
only:
|
||||||
- triggers
|
- triggers
|
||||||
image: ethcore/rust:beta
|
image: parity/rust:gitlab-ci
|
||||||
before_script:
|
before_script:
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
- export RUST_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep -v -e ^js -e ^\\. -e ^LICENSE -e ^README.md -e ^appveyor.yml -e ^test.sh -e ^windows/ -e ^scripts/ -e^mac/ -e ^nsis/ | wc -l)
|
- export RUST_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep -v -e ^js -e ^\\. -e ^LICENSE -e ^README.md -e ^appveyor.yml -e ^test.sh -e ^windows/ -e ^scripts/ -e^mac/ -e ^nsis/ | wc -l)
|
||||||
script:
|
script:
|
||||||
|
- rustup default beta
|
||||||
- export RUST_BACKTRACE=1
|
- export RUST_BACKTRACE=1
|
||||||
- if [ $RUST_FILES_MODIFIED -eq 0 ]; then echo "Skipping Rust tests since no Rust files modified."; else ./test.sh $CARGOFLAGS; fi
|
- if [ $RUST_FILES_MODIFIED -eq 0 ]; then echo "Skipping Rust tests since no Rust files modified."; else ./test.sh $CARGOFLAGS; fi
|
||||||
tags:
|
tags:
|
||||||
@@ -572,11 +609,12 @@ test-rust-nightly:
|
|||||||
stage: test
|
stage: test
|
||||||
only:
|
only:
|
||||||
- triggers
|
- triggers
|
||||||
image: ethcore/rust:nightly
|
image: parity/rust:gitlab-ci
|
||||||
before_script:
|
before_script:
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
- export RUST_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep -v -e ^js -e ^\\. -e ^LICENSE -e ^README.md -e ^appveyor.yml -e ^test.sh -e ^windows/ -e ^scripts/ -e^mac/ -e ^nsis/ | wc -l)
|
- export RUST_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep -v -e ^js -e ^\\. -e ^LICENSE -e ^README.md -e ^appveyor.yml -e ^test.sh -e ^windows/ -e ^scripts/ -e^mac/ -e ^nsis/ | wc -l)
|
||||||
script:
|
script:
|
||||||
|
- rustup default nightly
|
||||||
- export RUST_BACKTRACE=1
|
- export RUST_BACKTRACE=1
|
||||||
- if [ $RUST_FILES_MODIFIED -eq 0 ]; then echo "Skipping Rust tests since no Rust files modified."; else ./test.sh $CARGOFLAGS; fi
|
- if [ $RUST_FILES_MODIFIED -eq 0 ]; then echo "Skipping Rust tests since no Rust files modified."; else ./test.sh $CARGOFLAGS; fi
|
||||||
tags:
|
tags:
|
||||||
@@ -590,7 +628,7 @@ js-release:
|
|||||||
- beta
|
- beta
|
||||||
- stable
|
- stable
|
||||||
- tags
|
- tags
|
||||||
image: ethcore/rust:stable
|
image: parity/rust:gitlab-ci
|
||||||
before_script:
|
before_script:
|
||||||
- export JS_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep ^js/ | wc -l)
|
- export JS_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep ^js/ | wc -l)
|
||||||
- echo $JS_FILES_MODIFIED
|
- echo $JS_FILES_MODIFIED
|
||||||
@@ -604,7 +642,7 @@ push-release:
|
|||||||
stage: push-release
|
stage: push-release
|
||||||
only:
|
only:
|
||||||
- tags
|
- tags
|
||||||
image: ethcore/rust:stable
|
image: parity/rust:gitlab-ci
|
||||||
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
|
||||||
|
|||||||
3842
CHANGELOG.md
Normal file
3842
CHANGELOG.md
Normal file
File diff suppressed because it is too large
Load Diff
651
Cargo.lock
generated
651
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
description = "Parity Ethereum client"
|
description = "Parity Ethereum client"
|
||||||
name = "parity"
|
name = "parity"
|
||||||
version = "1.6.0"
|
version = "1.6.9"
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
authors = ["Parity Technologies <admin@parity.io>"]
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
|
||||||
@@ -24,8 +24,8 @@ serde_json = "0.9"
|
|||||||
app_dirs = "1.1.1"
|
app_dirs = "1.1.1"
|
||||||
fdlimit = "0.1"
|
fdlimit = "0.1"
|
||||||
hyper = { default-features = false, git = "https://github.com/ethcore/hyper" }
|
hyper = { default-features = false, git = "https://github.com/ethcore/hyper" }
|
||||||
ctrlc = { git = "https://github.com/ethcore/rust-ctrlc.git" }
|
ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" }
|
||||||
jsonrpc-core = { git = "https://github.com/ethcore/jsonrpc.git" }
|
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.6" }
|
||||||
ethsync = { path = "sync" }
|
ethsync = { path = "sync" }
|
||||||
ethcore = { path = "ethcore" }
|
ethcore = { path = "ethcore" }
|
||||||
ethcore-util = { path = "util" }
|
ethcore-util = { path = "util" }
|
||||||
|
|||||||
@@ -12,8 +12,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/paritytech/jsonrpc.git", branch = "parity-1.6" }
|
||||||
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc.git" }
|
jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.6" }
|
||||||
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"
|
||||||
@@ -22,7 +22,7 @@ serde = "0.9"
|
|||||||
serde_json = "0.9"
|
serde_json = "0.9"
|
||||||
serde_derive = "0.9"
|
serde_derive = "0.9"
|
||||||
linked-hash-map = "0.3"
|
linked-hash-map = "0.3"
|
||||||
parity-dapps-glue = "1.4"
|
parity-dapps-glue = "1.7"
|
||||||
base32 = "0.3"
|
base32 = "0.3"
|
||||||
mime = "0.2"
|
mime = "0.2"
|
||||||
mime_guess = "1.6.1"
|
mime_guess = "1.6.1"
|
||||||
|
|||||||
@@ -7,17 +7,17 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
|||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
quasi_codegen = { version = "0.11", optional = true }
|
quasi_codegen = { version = "0.32", optional = true }
|
||||||
syntex = { version = "0.33", optional = true }
|
syntex = { version = "0.58", optional = true }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
glob = { version = "0.2.11" }
|
glob = { version = "0.2.11" }
|
||||||
mime_guess = { version = "1.6.1" }
|
mime_guess = { version = "1.6.1" }
|
||||||
aster = { version = "0.17", default-features = false }
|
aster = { version = "0.41", default-features = false }
|
||||||
quasi = { version = "0.11", default-features = false }
|
quasi = { version = "0.32", default-features = false }
|
||||||
quasi_macros = { version = "0.11", optional = true }
|
quasi_macros = { version = "0.32", optional = true }
|
||||||
syntex = { version = "0.33", optional = true }
|
syntex = { version = "0.58", optional = true }
|
||||||
syntex_syntax = { version = "0.33", optional = true }
|
syntex_syntax = { version = "0.58", optional = true }
|
||||||
clippy = { version = "0.0.90", optional = true }
|
clippy = { version = "0.0.90", optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|||||||
@@ -25,13 +25,11 @@ mod inner {
|
|||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
let mut registry = syntex::Registry::new();
|
|
||||||
quasi_codegen::register(&mut registry);
|
|
||||||
|
|
||||||
let src = Path::new("src/lib.rs.in");
|
let src = Path::new("src/lib.rs.in");
|
||||||
let dst = Path::new(&out_dir).join("lib.rs");
|
let dst = Path::new(&out_dir).join("lib.rs");
|
||||||
|
|
||||||
registry.expand("", &src, &dst).unwrap();
|
quasi_codegen::expand(&src, &dst).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,9 +13,8 @@ pub mod inner {
|
|||||||
|
|
||||||
impl fold::Folder for StripAttributeFolder {
|
impl fold::Folder for StripAttributeFolder {
|
||||||
fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
|
fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
|
||||||
match attr.node.value.node {
|
if &*attr.value.name.as_str() == "webapp" {
|
||||||
ast::MetaItemKind::List(ref n, _) if n == &"webapp" => { return None; }
|
return None;
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(attr)
|
Some(attr)
|
||||||
|
|||||||
@@ -22,16 +22,12 @@ use self::mime_guess::guess_mime_type;
|
|||||||
use std::path::{self, Path, PathBuf};
|
use std::path::{self, Path, PathBuf};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use syntax::ast::{MetaItem, Item};
|
|
||||||
|
|
||||||
use syntax::ast;
|
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
|
use syntax::ast::{self, MetaItem, Item};
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use syntax::ext::base::{Annotatable, ExtCtxt};
|
use syntax::ext::base::{Annotatable, ExtCtxt};
|
||||||
use syntax::ptr::P;
|
use syntax::print::pprust::lit_to_string;
|
||||||
use syntax::print::pprust::{lit_to_string};
|
use syntax::symbol::InternedString;
|
||||||
use syntax::parse::token::{InternedString};
|
|
||||||
|
|
||||||
|
|
||||||
pub fn expand_webapp_implementation(
|
pub fn expand_webapp_implementation(
|
||||||
cx: &mut ExtCtxt,
|
cx: &mut ExtCtxt,
|
||||||
@@ -48,7 +44,7 @@ pub fn expand_webapp_implementation(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
let builder = aster::AstBuilder::new().span(span);
|
let builder = aster::AstBuilder::new().span(span);
|
||||||
implement_webapp(cx, &builder, &item, push);
|
implement_webapp(cx, &builder, item, push);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn implement_webapp(cx: &ExtCtxt, builder: &aster::AstBuilder, item: &Item, push: &mut FnMut(Annotatable)) {
|
fn implement_webapp(cx: &ExtCtxt, builder: &aster::AstBuilder, item: &Item, push: &mut FnMut(Annotatable)) {
|
||||||
@@ -117,11 +113,12 @@ fn implement_webapp(cx: &ExtCtxt, builder: &aster::AstBuilder, item: &Item, push
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn extract_path(cx: &ExtCtxt, item: &Item) -> String {
|
fn extract_path(cx: &ExtCtxt, item: &Item) -> String {
|
||||||
for meta_items in item.attrs().iter().filter_map(webapp_meta_items) {
|
for meta_items in item.attrs.iter().filter_map(webapp_meta_items) {
|
||||||
for meta_item in meta_items {
|
for meta_item in meta_items {
|
||||||
|
let is_path = &*meta_item.name.as_str() == "path";
|
||||||
match meta_item.node {
|
match meta_item.node {
|
||||||
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"path" => {
|
ast::MetaItemKind::NameValue(ref lit) if is_path => {
|
||||||
if let Some(s) = get_str_from_lit(cx, name, lit) {
|
if let Some(s) = get_str_from_lit(cx, lit) {
|
||||||
return s.deref().to_owned();
|
return s.deref().to_owned();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -134,14 +131,32 @@ fn extract_path(cx: &ExtCtxt, item: &Item) -> String {
|
|||||||
"web".to_owned()
|
"web".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_str_from_lit(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Option<InternedString> {
|
fn webapp_meta_items(attr: &ast::Attribute) -> Option<Vec<ast::MetaItem>> {
|
||||||
|
let is_webapp = &*attr.value.name.as_str() == "webapp";
|
||||||
|
match attr.value.node {
|
||||||
|
ast::MetaItemKind::List(ref items) if is_webapp => {
|
||||||
|
attr::mark_used(&attr);
|
||||||
|
Some(
|
||||||
|
items.iter()
|
||||||
|
.map(|item| item.node.clone())
|
||||||
|
.filter_map(|item| match item {
|
||||||
|
ast::NestedMetaItemKind::MetaItem(item) => Some(item),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_str_from_lit(cx: &ExtCtxt, lit: &ast::Lit) -> Option<InternedString> {
|
||||||
match lit.node {
|
match lit.node {
|
||||||
ast::LitKind::Str(ref s, _) => Some(s.clone()),
|
ast::LitKind::Str(ref s, _) => Some(s.clone().as_str()),
|
||||||
_ => {
|
_ => {
|
||||||
cx.span_err(
|
cx.span_err(
|
||||||
lit.span,
|
lit.span,
|
||||||
&format!("webapp annotation `{}` must be a string, not `{}`",
|
&format!("webapp annotation path must be a string, not `{}`",
|
||||||
name,
|
|
||||||
lit_to_string(lit)
|
lit_to_string(lit)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -150,16 +165,6 @@ fn get_str_from_lit(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Option<Interned
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn webapp_meta_items(attr: &ast::Attribute) -> Option<&[P<ast::MetaItem>]> {
|
|
||||||
match attr.node.value.node {
|
|
||||||
ast::MetaItemKind::List(ref name, ref items) if name == &"webapp" => {
|
|
||||||
attr::mark_used(&attr);
|
|
||||||
Some(items)
|
|
||||||
}
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_uri(path: &Path) -> String {
|
fn as_uri(path: &Path) -> String {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
for component in path.iter() {
|
for component in path.iter() {
|
||||||
@@ -169,7 +174,6 @@ fn as_uri(path: &Path) -> String {
|
|||||||
s[0..s.len()-1].into()
|
s[0..s.len()-1].into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_convert_path_separators_on_all_platforms() {
|
fn should_convert_path_separators_on_all_platforms() {
|
||||||
// given
|
// given
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ pub fn build(path: &str, dest: &str) {
|
|||||||
let child = platform::handle_fd(&mut Command::new(platform::NPM_CMD))
|
let child = platform::handle_fd(&mut Command::new(platform::NPM_CMD))
|
||||||
.arg("install")
|
.arg("install")
|
||||||
.arg("--no-progress")
|
.arg("--no-progress")
|
||||||
|
.arg("--ignore-scripts")
|
||||||
.current_dir(path)
|
.current_dir(path)
|
||||||
.status()
|
.status()
|
||||||
.unwrap_or_else(|e| die("Installing node.js dependencies with npm", e));
|
.unwrap_or_else(|e| die("Installing node.js dependencies with npm", e));
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
extern crate syntex;
|
extern crate syntex;
|
||||||
|
|
||||||
#[cfg(feature = "with-syntex")]
|
#[cfg(feature = "with-syntex")]
|
||||||
#[macro_use]
|
|
||||||
extern crate syntex_syntax as syntax;
|
extern crate syntex_syntax as syntax;
|
||||||
|
|
||||||
#[cfg(feature = "with-syntex")]
|
#[cfg(feature = "with-syntex")]
|
||||||
|
|||||||
@@ -39,7 +39,11 @@ pub struct RestApi {
|
|||||||
impl RestApi {
|
impl RestApi {
|
||||||
pub fn new(cors_domains: Vec<String>, endpoints: Arc<Endpoints>, fetcher: Arc<Fetcher>) -> Box<Endpoint> {
|
pub fn new(cors_domains: Vec<String>, endpoints: Arc<Endpoints>, fetcher: Arc<Fetcher>) -> Box<Endpoint> {
|
||||||
Box::new(RestApi {
|
Box::new(RestApi {
|
||||||
cors_domains: Some(cors_domains.into_iter().map(AccessControlAllowOrigin::Value).collect()),
|
cors_domains: Some(cors_domains.into_iter().map(|domain| match domain.as_ref() {
|
||||||
|
"all" | "*" | "any" => AccessControlAllowOrigin::Any,
|
||||||
|
"null" => AccessControlAllowOrigin::Null,
|
||||||
|
other => AccessControlAllowOrigin::Value(other.into()),
|
||||||
|
}).collect()),
|
||||||
endpoints: endpoints,
|
endpoints: endpoints,
|
||||||
fetcher: fetcher,
|
fetcher: fetcher,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ pub struct ServerBuilder<T: Fetch = FetchClient> {
|
|||||||
web_proxy_tokens: Arc<WebProxyTokens>,
|
web_proxy_tokens: Arc<WebProxyTokens>,
|
||||||
signer_address: Option<(String, u16)>,
|
signer_address: Option<(String, u16)>,
|
||||||
allowed_hosts: Option<Vec<String>>,
|
allowed_hosts: Option<Vec<String>>,
|
||||||
|
extra_cors: Option<Vec<String>>,
|
||||||
remote: Remote,
|
remote: Remote,
|
||||||
fetch: Option<T>,
|
fetch: Option<T>,
|
||||||
}
|
}
|
||||||
@@ -126,6 +127,7 @@ impl ServerBuilder {
|
|||||||
web_proxy_tokens: Arc::new(|_| false),
|
web_proxy_tokens: Arc::new(|_| false),
|
||||||
signer_address: None,
|
signer_address: None,
|
||||||
allowed_hosts: Some(vec![]),
|
allowed_hosts: Some(vec![]),
|
||||||
|
extra_cors: None,
|
||||||
remote: remote,
|
remote: remote,
|
||||||
fetch: None,
|
fetch: None,
|
||||||
}
|
}
|
||||||
@@ -143,6 +145,7 @@ impl<T: Fetch> ServerBuilder<T> {
|
|||||||
web_proxy_tokens: self.web_proxy_tokens,
|
web_proxy_tokens: self.web_proxy_tokens,
|
||||||
signer_address: self.signer_address,
|
signer_address: self.signer_address,
|
||||||
allowed_hosts: self.allowed_hosts,
|
allowed_hosts: self.allowed_hosts,
|
||||||
|
extra_cors: self.extra_cors,
|
||||||
remote: self.remote,
|
remote: self.remote,
|
||||||
fetch: Some(fetch),
|
fetch: Some(fetch),
|
||||||
}
|
}
|
||||||
@@ -174,6 +177,13 @@ impl<T: Fetch> ServerBuilder<T> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extra cors headers.
|
||||||
|
/// `None` - no additional CORS URLs
|
||||||
|
pub fn extra_cors_headers(mut self, cors: Option<Vec<String>>) -> Self {
|
||||||
|
self.extra_cors = cors;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Change extra dapps paths (apart from `dapps_path`)
|
/// Change extra dapps paths (apart from `dapps_path`)
|
||||||
pub fn extra_dapps<P: AsRef<Path>>(mut self, extra_dapps: &[P]) -> Self {
|
pub fn extra_dapps<P: AsRef<Path>>(mut self, extra_dapps: &[P]) -> Self {
|
||||||
self.extra_dapps = extra_dapps.iter().map(|p| p.as_ref().to_owned()).collect();
|
self.extra_dapps = extra_dapps.iter().map(|p| p.as_ref().to_owned()).collect();
|
||||||
@@ -187,6 +197,7 @@ impl<T: Fetch> ServerBuilder<T> {
|
|||||||
Server::start_http(
|
Server::start_http(
|
||||||
addr,
|
addr,
|
||||||
self.allowed_hosts,
|
self.allowed_hosts,
|
||||||
|
self.extra_cors,
|
||||||
NoAuth,
|
NoAuth,
|
||||||
handler,
|
handler,
|
||||||
self.dapps_path,
|
self.dapps_path,
|
||||||
@@ -207,6 +218,7 @@ impl<T: Fetch> ServerBuilder<T> {
|
|||||||
Server::start_http(
|
Server::start_http(
|
||||||
addr,
|
addr,
|
||||||
self.allowed_hosts,
|
self.allowed_hosts,
|
||||||
|
self.extra_cors,
|
||||||
HttpBasicAuth::single_user(username, password),
|
HttpBasicAuth::single_user(username, password),
|
||||||
handler,
|
handler,
|
||||||
self.dapps_path,
|
self.dapps_path,
|
||||||
@@ -251,8 +263,8 @@ impl Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a list of CORS domains for API endpoint.
|
/// Returns a list of CORS domains for API endpoint.
|
||||||
fn cors_domains(signer_address: Option<(String, u16)>) -> Vec<String> {
|
fn cors_domains(signer_address: Option<(String, u16)>, extra_cors: Option<Vec<String>>) -> Vec<String> {
|
||||||
match signer_address {
|
let basic_cors = match signer_address {
|
||||||
Some(signer_address) => vec![
|
Some(signer_address) => vec![
|
||||||
format!("http://{}{}", HOME_PAGE, DAPPS_DOMAIN),
|
format!("http://{}{}", HOME_PAGE, DAPPS_DOMAIN),
|
||||||
format!("http://{}{}:{}", HOME_PAGE, DAPPS_DOMAIN, signer_address.1),
|
format!("http://{}{}:{}", HOME_PAGE, DAPPS_DOMAIN, signer_address.1),
|
||||||
@@ -260,15 +272,20 @@ impl Server {
|
|||||||
format!("https://{}{}", HOME_PAGE, DAPPS_DOMAIN),
|
format!("https://{}{}", HOME_PAGE, DAPPS_DOMAIN),
|
||||||
format!("https://{}{}:{}", HOME_PAGE, DAPPS_DOMAIN, signer_address.1),
|
format!("https://{}{}:{}", HOME_PAGE, DAPPS_DOMAIN, signer_address.1),
|
||||||
format!("https://{}", address(&signer_address)),
|
format!("https://{}", address(&signer_address)),
|
||||||
|
|
||||||
],
|
],
|
||||||
None => vec![],
|
None => vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
match extra_cors {
|
||||||
|
None => basic_cors,
|
||||||
|
Some(extra_cors) => basic_cors.into_iter().chain(extra_cors).collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_http<A: Authorization + 'static, F: Fetch, T: Middleware<Metadata>>(
|
fn start_http<A: Authorization + 'static, F: Fetch, T: Middleware<Metadata>>(
|
||||||
addr: &SocketAddr,
|
addr: &SocketAddr,
|
||||||
hosts: Option<Vec<String>>,
|
hosts: Option<Vec<String>>,
|
||||||
|
extra_cors: Option<Vec<String>>,
|
||||||
authorization: A,
|
authorization: A,
|
||||||
handler: RpcHandler<Metadata, T>,
|
handler: RpcHandler<Metadata, T>,
|
||||||
dapps_path: PathBuf,
|
dapps_path: PathBuf,
|
||||||
@@ -297,7 +314,7 @@ impl Server {
|
|||||||
remote.clone(),
|
remote.clone(),
|
||||||
fetch.clone(),
|
fetch.clone(),
|
||||||
));
|
));
|
||||||
let cors_domains = Self::cors_domains(signer_address.clone());
|
let cors_domains = Self::cors_domains(signer_address.clone(), extra_cors);
|
||||||
|
|
||||||
let special = Arc::new({
|
let special = Arc::new({
|
||||||
let mut special = HashMap::new();
|
let mut special = HashMap::new();
|
||||||
@@ -413,8 +430,9 @@ mod util_tests {
|
|||||||
// given
|
// given
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let none = Server::cors_domains(None);
|
let none = Server::cors_domains(None, None);
|
||||||
let some = Server::cors_domains(Some(("127.0.0.1".into(), 18180)));
|
let some = Server::cors_domains(Some(("127.0.0.1".into(), 18180)), None);
|
||||||
|
let extra = Server::cors_domains(None, Some(vec!["all".to_owned()]));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(none, Vec::<String>::new());
|
assert_eq!(none, Vec::<String>::new());
|
||||||
@@ -425,7 +443,7 @@ mod util_tests {
|
|||||||
"https://parity.web3.site".into(),
|
"https://parity.web3.site".into(),
|
||||||
"https://parity.web3.site:18180".into(),
|
"https://parity.web3.site:18180".into(),
|
||||||
"https://127.0.0.1:18180".into()
|
"https://127.0.0.1:18180".into()
|
||||||
|
|
||||||
]);
|
]);
|
||||||
|
assert_eq!(extra, vec!["all".to_owned()]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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/>.
|
||||||
|
|
||||||
use tests::helpers::{serve, serve_with_registrar, request, assert_security_headers};
|
use tests::helpers::{serve, serve_with_registrar, serve_extra_cors, request, assert_security_headers};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_return_error() {
|
fn should_return_error() {
|
||||||
@@ -212,3 +212,25 @@ fn should_return_signer_port_cors_headers_for_home_parity_with_port() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_return_extra_cors_headers() {
|
||||||
|
// given
|
||||||
|
let server = serve_extra_cors(Some(vec!["all".to_owned()]));
|
||||||
|
|
||||||
|
// when
|
||||||
|
let response = request(server,
|
||||||
|
"\
|
||||||
|
POST /api/ping HTTP/1.1\r\n\
|
||||||
|
Host: localhost:8080\r\n\
|
||||||
|
Origin: http://somedomain.io\r\n\
|
||||||
|
Connection: close\r\n\
|
||||||
|
\r\n\
|
||||||
|
{}
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
// then
|
||||||
|
response.assert_status("HTTP/1.1 200 OK");
|
||||||
|
response.assert_header("Access-Control-Allow-Origin", "http://somedomain.io");
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -109,6 +109,10 @@ pub fn serve_hosts(hosts: Option<Vec<String>>) -> ServerLoop {
|
|||||||
init_server(|builder| builder.allowed_hosts(hosts), Default::default(), Remote::new_sync()).0
|
init_server(|builder| builder.allowed_hosts(hosts), Default::default(), Remote::new_sync()).0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn serve_extra_cors(extra_cors: Option<Vec<String>>) -> ServerLoop {
|
||||||
|
init_server(|builder| builder.allowed_hosts(None).extra_cors_headers(extra_cors), Default::default(), Remote::new_sync()).0
|
||||||
|
}
|
||||||
|
|
||||||
pub fn serve_with_registrar() -> (ServerLoop, Arc<FakeRegistrar>) {
|
pub fn serve_with_registrar() -> (ServerLoop, Arc<FakeRegistrar>) {
|
||||||
init_server(|builder| builder.allowed_hosts(None), Default::default(), Remote::new_sync())
|
init_server(|builder| builder.allowed_hosts(None), Default::default(), Remote::new_sync())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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/paritytech/js-precompiled.git", branch = "stable", optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
no-precompiled-js = ["parity-ui-dev"]
|
no-precompiled-js = ["parity-ui-dev"]
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ ethcore-ipc-codegen = { path = "../ipc/codegen" }
|
|||||||
clippy = { version = "0.0.103", optional = true}
|
clippy = { version = "0.0.103", optional = true}
|
||||||
ethcore-devtools = { path = "../devtools" }
|
ethcore-devtools = { path = "../devtools" }
|
||||||
ethcore-ipc = { path = "../ipc/rpc" }
|
ethcore-ipc = { path = "../ipc/rpc" }
|
||||||
rocksdb = { git = "https://github.com/ethcore/rust-rocksdb" }
|
rocksdb = { git = "https://github.com/paritytech/rust-rocksdb" }
|
||||||
semver = "0.5"
|
semver = "0.5"
|
||||||
ethcore-ipc-nano = { path = "../ipc/nano" }
|
ethcore-ipc-nano = { path = "../ipc/nano" }
|
||||||
nanomsg = { git = "https://github.com/ethcore/nanomsg.rs.git" }
|
nanomsg = { git = "https://github.com/paritytech/nanomsg.rs.git" }
|
||||||
crossbeam = "0.2"
|
crossbeam = "0.2"
|
||||||
ethcore-util = { path = "../util" }
|
ethcore-util = { path = "../util" }
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ RUN apt-get update && \
|
|||||||
# show backtraces
|
# show backtraces
|
||||||
RUST_BACKTRACE=1 && \
|
RUST_BACKTRACE=1 && \
|
||||||
# build parity
|
# build parity
|
||||||
cd /build&&git clone https://github.com/ethcore/parity && \
|
cd /build&&git clone https://github.com/paritytech/parity && \
|
||||||
cd parity && \
|
cd parity && \
|
||||||
git pull&& \
|
git pull&& \
|
||||||
git checkout $BUILD_TAG && \
|
git checkout $BUILD_TAG && \
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ byteorder = "1.0"
|
|||||||
transient-hashmap = "0.1"
|
transient-hashmap = "0.1"
|
||||||
linked-hash-map = "0.3.0"
|
linked-hash-map = "0.3.0"
|
||||||
lru-cache = "0.1.0"
|
lru-cache = "0.1.0"
|
||||||
ethabi = "1.0.0"
|
itertools = "0.5"
|
||||||
|
ethabi = "1.0"
|
||||||
evmjit = { path = "../evmjit", optional = true }
|
evmjit = { path = "../evmjit", optional = true }
|
||||||
clippy = { version = "0.0.103", optional = true}
|
clippy = { version = "0.0.103", optional = true}
|
||||||
ethash = { path = "../ethash" }
|
ethash = { path = "../ethash" }
|
||||||
@@ -46,7 +47,7 @@ hardware-wallet = { path = "../hw" }
|
|||||||
stats = { path = "../util/stats" }
|
stats = { path = "../util/stats" }
|
||||||
|
|
||||||
[dependencies.hyper]
|
[dependencies.hyper]
|
||||||
git = "https://github.com/ethcore/hyper"
|
git = "https://github.com/paritytech/hyper"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
"timestamp": "0x00",
|
"timestamp": "0x00",
|
||||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"extraData": "0x",
|
"extraData": "0x",
|
||||||
"gasLimit": "0x2fefd8"
|
"gasLimit": "0x222222"
|
||||||
},
|
},
|
||||||
"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 } } } },
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
"eip160Transition": 3000000,
|
"eip160Transition": 3000000,
|
||||||
"ecip1010PauseTransition": 3000000,
|
"ecip1010PauseTransition": 3000000,
|
||||||
"ecip1010ContinueTransition": 5000000,
|
"ecip1010ContinueTransition": 5000000,
|
||||||
|
"ecip1017EraRounds": 5000000,
|
||||||
|
|
||||||
"eip161abcTransition": "0x7fffffffffffffff",
|
"eip161abcTransition": "0x7fffffffffffffff",
|
||||||
"eip161dTransition": "0x7fffffffffffffff"
|
"eip161dTransition": "0x7fffffffffffffff"
|
||||||
@@ -53,7 +54,9 @@
|
|||||||
"enode://5fbfb426fbb46f8b8c1bd3dd140f5b511da558cd37d60844b525909ab82e13a25ee722293c829e52cb65c2305b1637fa9a2ea4d6634a224d5f400bfe244ac0de@162.243.55.45:30303",
|
"enode://5fbfb426fbb46f8b8c1bd3dd140f5b511da558cd37d60844b525909ab82e13a25ee722293c829e52cb65c2305b1637fa9a2ea4d6634a224d5f400bfe244ac0de@162.243.55.45:30303",
|
||||||
"enode://42d8f29d1db5f4b2947cd5c3d76c6d0d3697e6b9b3430c3d41e46b4bb77655433aeedc25d4b4ea9d8214b6a43008ba67199374a9b53633301bca0cd20c6928ab@104.155.176.151:30303",
|
"enode://42d8f29d1db5f4b2947cd5c3d76c6d0d3697e6b9b3430c3d41e46b4bb77655433aeedc25d4b4ea9d8214b6a43008ba67199374a9b53633301bca0cd20c6928ab@104.155.176.151:30303",
|
||||||
"enode://814920f1ec9510aa9ea1c8f79d8b6e6a462045f09caa2ae4055b0f34f7416fca6facd3dd45f1cf1673c0209e0503f02776b8ff94020e98b6679a0dc561b4eba0@104.154.136.117:30303",
|
"enode://814920f1ec9510aa9ea1c8f79d8b6e6a462045f09caa2ae4055b0f34f7416fca6facd3dd45f1cf1673c0209e0503f02776b8ff94020e98b6679a0dc561b4eba0@104.154.136.117:30303",
|
||||||
"enode://72e445f4e89c0f476d404bc40478b0df83a5b500d2d2e850e08eb1af0cd464ab86db6160d0fde64bd77d5f0d33507ae19035671b3c74fec126d6e28787669740@104.198.71.200:30303"
|
"enode://72e445f4e89c0f476d404bc40478b0df83a5b500d2d2e850e08eb1af0cd464ab86db6160d0fde64bd77d5f0d33507ae19035671b3c74fec126d6e28787669740@104.198.71.200:30303",
|
||||||
|
"enode://39abab9d2a41f53298c0c9dc6bbca57b0840c3ba9dccf42aa27316addc1b7e56ade32a0a9f7f52d6c5db4fe74d8824bcedfeaecf1a4e533cacb71cf8100a9442@144.76.238.49:30303",
|
||||||
|
"enode://f50e675a34f471af2438b921914b5f06499c7438f3146f6b8936f1faeb50b8a91d0d0c24fb05a66f05865cd58c24da3e664d0def806172ddd0d4c5bdbf37747e@144.76.238.49:30306"
|
||||||
],
|
],
|
||||||
"accounts": {
|
"accounts": {
|
||||||
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||||
|
|||||||
@@ -15,11 +15,11 @@
|
|||||||
"difficultyHardforkTransition": "0x59d9",
|
"difficultyHardforkTransition": "0x59d9",
|
||||||
"difficultyHardforkBoundDivisor": "0x0200",
|
"difficultyHardforkBoundDivisor": "0x0200",
|
||||||
"bombDefuseTransition": "0x30d40",
|
"bombDefuseTransition": "0x30d40",
|
||||||
"eip150Transition": "0x7fffffffffffffff",
|
"eip150Transition": "0x927C0",
|
||||||
"eip155Transition": "0x7fffffffffffffff",
|
"eip155Transition": "0x927C0",
|
||||||
"eip160Transition": "0x7fffffffffffffff",
|
"eip160Transition": "0x927C0",
|
||||||
"eip161abcTransition": "0x7fffffffffffffff",
|
"eip161abcTransition": "0x927C0",
|
||||||
"eip161dTransition": "0x7fffffffffffffff"
|
"eip161dTransition": "0x927C0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -28,6 +28,7 @@
|
|||||||
"maximumExtraDataSize": "0x20",
|
"maximumExtraDataSize": "0x20",
|
||||||
"minGasLimit": "0x1388",
|
"minGasLimit": "0x1388",
|
||||||
"networkID": "0x1",
|
"networkID": "0x1",
|
||||||
|
"chainID": "0x2",
|
||||||
"subprotocolName": "exp",
|
"subprotocolName": "exp",
|
||||||
"eip98Transition": "0x7fffffffffffff"
|
"eip98Transition": "0x7fffffffffffff"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -23,14 +23,18 @@
|
|||||||
|
|
||||||
"0x00a0a24b9f0e5ec7aa4c7389b8302fd0123194de"
|
"0x00a0a24b9f0e5ec7aa4c7389b8302fd0123194de"
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"validateScoreTransition": 1000000,
|
||||||
|
"eip155Transition": 1000000,
|
||||||
|
"validateStepTransition": 1500000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"params": {
|
"params": {
|
||||||
"maximumExtraDataSize": "0x20",
|
"maximumExtraDataSize": "0x20",
|
||||||
"minGasLimit": "0x1388",
|
"minGasLimit": "0x1388",
|
||||||
"networkID" : "0x2A"
|
"networkID" : "0x2A",
|
||||||
|
"validateReceiptsTransition" : 1000000
|
||||||
},
|
},
|
||||||
"genesis": {
|
"genesis": {
|
||||||
"seal": {
|
"seal": {
|
||||||
|
|||||||
@@ -25,8 +25,8 @@
|
|||||||
"maximumExtraDataSize": "0x20",
|
"maximumExtraDataSize": "0x20",
|
||||||
"minGasLimit": "0x1388",
|
"minGasLimit": "0x1388",
|
||||||
"networkID" : "0x3",
|
"networkID" : "0x3",
|
||||||
"forkBlock": 333922,
|
"forkBlock": 641350,
|
||||||
"forkCanonHash": "0x8737eb141d4f05db57af63fc8d3b4d4d8f9cddb0c4e1ab855de8c288fdc1924f",
|
"forkCanonHash": "0x8033403e9fe5811a7b6d6b469905915de1c59207ce2172cbcf5d6ff14fa6a2eb",
|
||||||
"eip98Transition": "0x7fffffffffffff"
|
"eip98Transition": "0x7fffffffffffff"
|
||||||
},
|
},
|
||||||
"genesis": {
|
"genesis": {
|
||||||
@@ -44,11 +44,8 @@
|
|||||||
"gasLimit": "0x1000000"
|
"gasLimit": "0x1000000"
|
||||||
},
|
},
|
||||||
"nodes": [
|
"nodes": [
|
||||||
"enode://a22f0977ce02653bf95e38730106356342df48b5222e2c2a1a6f9ef34769bf593bae9ca0a888cf60839edd52efc1b6e393c63a57d76f4c4fe14e641f1f9e637e@128.199.55.137:30303",
|
"enode://20c9ad97c081d63397d7b685a412227a40e23c8bdc6688c6f37e97cfbc22d2b4d1db1510d8f61e6a8866ad7f0e17c02b14182d37ea7c3c8b9c2683aeb6b733a1@52.169.14.227:30303",
|
||||||
"enode://012239fccf3ff1d92b036983a430cb6705c6528c96c0354413f8854802138e5135c084ab36e7c54efb621c46728df8c3a6f4c1db9bb48a1330efe3f82f2dd7a6@52.169.94.142:30303",
|
"enode://6ce05930c72abc632c58e2e4324f7c7ea478cec0ed4fa2528982cf34483094e9cbc9216e7aa349691242576d552a2a56aaeae426c5303ded677ce455ba1acd9d@13.84.180.240: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 } } } },
|
||||||
|
|||||||
@@ -139,6 +139,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"params": {
|
"params": {
|
||||||
|
"eip98Transition": "0x7fffffffffffffff",
|
||||||
"accountStartNonce": "0x00",
|
"accountStartNonce": "0x00",
|
||||||
"maximumExtraDataSize": "0x20",
|
"maximumExtraDataSize": "0x20",
|
||||||
"minGasLimit": "0x1388",
|
"minGasLimit": "0x1388",
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
"timestamp": "0x00",
|
"timestamp": "0x00",
|
||||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"extraData": "0x",
|
"extraData": "0x",
|
||||||
"gasLimit": "0x2fefd8"
|
"gasLimit": "0x222222"
|
||||||
},
|
},
|
||||||
"accounts": {
|
"accounts": {
|
||||||
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
"timestamp": "0x00",
|
"timestamp": "0x00",
|
||||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"extraData": "0x",
|
"extraData": "0x",
|
||||||
"gasLimit": "0x2fefd8"
|
"gasLimit": "0x222222"
|
||||||
},
|
},
|
||||||
"accounts": {
|
"accounts": {
|
||||||
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||||
|
|||||||
42
ethcore/res/validator_multi.json
Normal file
42
ethcore/res/validator_multi.json
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"name": "TestMutiValidator",
|
||||||
|
"engine": {
|
||||||
|
"basicAuthority": {
|
||||||
|
"params": {
|
||||||
|
"gasLimitBoundDivisor": "0x0400",
|
||||||
|
"durationLimit": "0x0d",
|
||||||
|
"validators": {
|
||||||
|
"multi": {
|
||||||
|
"0": { "list": ["0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1"] },
|
||||||
|
"2": { "list": ["0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e"] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"accountStartNonce": "0x0",
|
||||||
|
"maximumExtraDataSize": "0x20",
|
||||||
|
"minGasLimit": "0x1388",
|
||||||
|
"networkID" : "0x69"
|
||||||
|
},
|
||||||
|
"genesis": {
|
||||||
|
"seal": {
|
||||||
|
"generic": "0xc180"
|
||||||
|
},
|
||||||
|
"difficulty": "0x20000",
|
||||||
|
"author": "0x0000000000000000000000000000000000000000",
|
||||||
|
"timestamp": "0x00",
|
||||||
|
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"extraData": "0x",
|
||||||
|
"gasLimit": "0x2fefd8"
|
||||||
|
},
|
||||||
|
"accounts": {
|
||||||
|
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||||
|
"0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||||
|
"0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||||
|
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
|
||||||
|
"0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1": { "balance": "99999999999999999999999" },
|
||||||
|
"0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e": { "balance": "99999999999999999999999" }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -123,6 +123,8 @@ pub struct AccountProvider {
|
|||||||
transient_sstore: EthMultiStore,
|
transient_sstore: EthMultiStore,
|
||||||
/// Accounts in hardware wallets.
|
/// Accounts in hardware wallets.
|
||||||
hardware_store: Option<HardwareWalletManager>,
|
hardware_store: Option<HardwareWalletManager>,
|
||||||
|
/// Disallowed accounts.
|
||||||
|
blacklisted_accounts: Vec<Address>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Account management settings.
|
/// Account management settings.
|
||||||
@@ -131,6 +133,8 @@ pub struct AccountProviderSettings {
|
|||||||
pub enable_hardware_wallets: bool,
|
pub enable_hardware_wallets: bool,
|
||||||
/// Use the classic chain key on the hardware wallet.
|
/// Use the classic chain key on the hardware wallet.
|
||||||
pub hardware_wallet_classic_key: bool,
|
pub hardware_wallet_classic_key: bool,
|
||||||
|
/// Disallowed accounts.
|
||||||
|
pub blacklisted_accounts: Vec<Address>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for AccountProviderSettings {
|
impl Default for AccountProviderSettings {
|
||||||
@@ -138,6 +142,7 @@ impl Default for AccountProviderSettings {
|
|||||||
AccountProviderSettings {
|
AccountProviderSettings {
|
||||||
enable_hardware_wallets: false,
|
enable_hardware_wallets: false,
|
||||||
hardware_wallet_classic_key: false,
|
hardware_wallet_classic_key: false,
|
||||||
|
blacklisted_accounts: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,16 +157,24 @@ impl AccountProvider {
|
|||||||
manager.set_key_path(if settings.hardware_wallet_classic_key { KeyPath::EthereumClassic } else { KeyPath::Ethereum });
|
manager.set_key_path(if settings.hardware_wallet_classic_key { KeyPath::EthereumClassic } else { KeyPath::Ethereum });
|
||||||
hardware_store = Some(manager)
|
hardware_store = Some(manager)
|
||||||
},
|
},
|
||||||
Err(e) => warn!("Error initializing hardware wallets: {}", e),
|
Err(e) => debug!("Error initializing hardware wallets: {}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove blacklisted accounts from address book.
|
||||||
|
let mut address_book = AddressBook::new(&sstore.local_path());
|
||||||
|
for addr in &settings.blacklisted_accounts {
|
||||||
|
address_book.remove(*addr);
|
||||||
|
}
|
||||||
|
|
||||||
AccountProvider {
|
AccountProvider {
|
||||||
unlocked: RwLock::new(HashMap::new()),
|
unlocked: RwLock::new(HashMap::new()),
|
||||||
address_book: RwLock::new(AddressBook::new(&sstore.local_path())),
|
address_book: RwLock::new(address_book),
|
||||||
dapps_settings: RwLock::new(DappsSettingsStore::new(&sstore.local_path())),
|
dapps_settings: RwLock::new(DappsSettingsStore::new(&sstore.local_path())),
|
||||||
sstore: sstore,
|
sstore: sstore,
|
||||||
transient_sstore: transient_sstore(),
|
transient_sstore: transient_sstore(),
|
||||||
hardware_store: hardware_store,
|
hardware_store: hardware_store,
|
||||||
|
blacklisted_accounts: settings.blacklisted_accounts,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,6 +187,7 @@ impl AccountProvider {
|
|||||||
sstore: Box::new(EthStore::open(Box::new(MemoryDirectory::default())).expect("MemoryDirectory load always succeeds; qed")),
|
sstore: Box::new(EthStore::open(Box::new(MemoryDirectory::default())).expect("MemoryDirectory load always succeeds; qed")),
|
||||||
transient_sstore: transient_sstore(),
|
transient_sstore: transient_sstore(),
|
||||||
hardware_store: None,
|
hardware_store: None,
|
||||||
|
blacklisted_accounts: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,6 +209,10 @@ impl AccountProvider {
|
|||||||
/// Does not unlock account!
|
/// Does not unlock account!
|
||||||
pub fn insert_account(&self, secret: Secret, password: &str) -> Result<Address, Error> {
|
pub fn insert_account(&self, secret: Secret, password: &str) -> Result<Address, Error> {
|
||||||
let account = self.sstore.insert_account(SecretVaultRef::Root, secret, password)?;
|
let account = self.sstore.insert_account(SecretVaultRef::Root, secret, password)?;
|
||||||
|
if self.blacklisted_accounts.contains(&account.address) {
|
||||||
|
self.sstore.remove_account(&account, password)?;
|
||||||
|
return Err(SSError::InvalidAccount.into());
|
||||||
|
}
|
||||||
Ok(account.address)
|
Ok(account.address)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,6 +239,10 @@ impl AccountProvider {
|
|||||||
/// Import a new presale wallet.
|
/// Import a new presale wallet.
|
||||||
pub fn import_wallet(&self, json: &[u8], password: &str) -> Result<Address, Error> {
|
pub fn import_wallet(&self, json: &[u8], password: &str) -> Result<Address, Error> {
|
||||||
let account = self.sstore.import_wallet(SecretVaultRef::Root, json, password)?;
|
let account = self.sstore.import_wallet(SecretVaultRef::Root, json, password)?;
|
||||||
|
if self.blacklisted_accounts.contains(&account.address) {
|
||||||
|
self.sstore.remove_account(&account, password)?;
|
||||||
|
return Err(SSError::InvalidAccount.into());
|
||||||
|
}
|
||||||
Ok(Address::from(account.address).into())
|
Ok(Address::from(account.address).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +254,12 @@ impl AccountProvider {
|
|||||||
/// Returns addresses of all accounts.
|
/// Returns addresses of all accounts.
|
||||||
pub fn accounts(&self) -> Result<Vec<Address>, Error> {
|
pub fn accounts(&self) -> Result<Vec<Address>, Error> {
|
||||||
let accounts = self.sstore.accounts()?;
|
let accounts = self.sstore.accounts()?;
|
||||||
Ok(accounts.into_iter().map(|a| a.address).collect())
|
Ok(accounts
|
||||||
|
.into_iter()
|
||||||
|
.map(|a| a.address)
|
||||||
|
.filter(|address| !self.blacklisted_accounts.contains(address))
|
||||||
|
.collect()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns addresses of hardware accounts.
|
/// Returns addresses of hardware accounts.
|
||||||
@@ -434,6 +461,7 @@ impl AccountProvider {
|
|||||||
pub fn accounts_info(&self) -> Result<HashMap<Address, AccountMeta>, Error> {
|
pub fn accounts_info(&self) -> Result<HashMap<Address, AccountMeta>, Error> {
|
||||||
let r = self.sstore.accounts()?
|
let r = self.sstore.accounts()?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
.filter(|a| !self.blacklisted_accounts.contains(&a.address))
|
||||||
.map(|a| (a.address.clone(), self.account_meta(a.address).ok().unwrap_or_default()))
|
.map(|a| (a.address.clone(), self.account_meta(a.address).ok().unwrap_or_default()))
|
||||||
.collect();
|
.collect();
|
||||||
Ok(r)
|
Ok(r)
|
||||||
@@ -712,7 +740,7 @@ impl AccountProvider {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::{AccountProvider, Unlock, DappId};
|
use super::{AccountProvider, Unlock, DappId};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use ethstore::ethkey::{Generator, Random};
|
use ethstore::ethkey::{Generator, Random, Address};
|
||||||
use ethstore::{StoreAccountRef, Derivation};
|
use ethstore::{StoreAccountRef, Derivation};
|
||||||
use util::H256;
|
use util::H256;
|
||||||
|
|
||||||
@@ -927,4 +955,16 @@ mod tests {
|
|||||||
assert_eq!(ap.new_dapps_default_address().unwrap(), address);
|
assert_eq!(ap.new_dapps_default_address().unwrap(), address);
|
||||||
assert_eq!(ap.dapp_default_address("app1".into()).unwrap(), address);
|
assert_eq!(ap.dapp_default_address("app1".into()).unwrap(), address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_not_return_blacklisted_account() {
|
||||||
|
// given
|
||||||
|
let mut ap = AccountProvider::transient_provider();
|
||||||
|
let acc = ap.new_account("test").unwrap();
|
||||||
|
ap.blacklisted_accounts = vec![acc];
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert_eq!(ap.accounts_info().unwrap().keys().cloned().collect::<Vec<Address>>(), vec![]);
|
||||||
|
assert_eq!(ap.accounts().unwrap(), vec![]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -493,6 +493,16 @@ impl LockedBlock {
|
|||||||
_ => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }),
|
_ => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove state root from transaction receipts to make them EIP-98 compatible.
|
||||||
|
pub fn strip_receipts(self) -> LockedBlock {
|
||||||
|
let mut block = self;
|
||||||
|
for receipt in &mut block.block.receipts {
|
||||||
|
receipt.state_root = None;
|
||||||
|
}
|
||||||
|
block.block.header.set_receipts_root(ordered_trie_root(block.block.receipts.iter().map(|r| r.rlp_bytes().to_vec())));
|
||||||
|
block
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drain for LockedBlock {
|
impl Drain for LockedBlock {
|
||||||
@@ -553,7 +563,6 @@ pub fn enact(
|
|||||||
b.set_extra_data(header.extra_data().clone()).unwrap_or_else(|e| warn!("Couldn't set extradata: {}. Ignoring.", e));
|
b.set_extra_data(header.extra_data().clone()).unwrap_or_else(|e| warn!("Couldn't set extradata: {}. Ignoring.", e));
|
||||||
b.set_uncles_hash(header.uncles_hash().clone());
|
b.set_uncles_hash(header.uncles_hash().clone());
|
||||||
b.set_transactions_root(header.transactions_root().clone());
|
b.set_transactions_root(header.transactions_root().clone());
|
||||||
b.set_receipts_root(header.receipts_root().clone());
|
|
||||||
|
|
||||||
push_transactions(&mut b, transactions)?;
|
push_transactions(&mut b, transactions)?;
|
||||||
for u in uncles {
|
for u in uncles {
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ impl Client {
|
|||||||
if let Some(reg_addr) = client.additional_params().get("registrar").and_then(|s| Address::from_str(s).ok()) {
|
if let Some(reg_addr) = client.additional_params().get("registrar").and_then(|s| Address::from_str(s).ok()) {
|
||||||
trace!(target: "client", "Found registrar at {}", reg_addr);
|
trace!(target: "client", "Found registrar at {}", reg_addr);
|
||||||
let weak = Arc::downgrade(&client);
|
let weak = Arc::downgrade(&client);
|
||||||
let registrar = Registry::new(reg_addr, move |a, d| weak.upgrade().ok_or("No client!".into()).and_then(|c| c.call_contract(a, d)));
|
let registrar = Registry::new(reg_addr, move |a, d| weak.upgrade().ok_or("No client!".into()).and_then(|c| c.call_contract(BlockId::Latest, a, d)));
|
||||||
*client.registrar.lock() = Some(registrar);
|
*client.registrar.lock() = Some(registrar);
|
||||||
}
|
}
|
||||||
Ok(client)
|
Ok(client)
|
||||||
@@ -355,7 +355,7 @@ impl Client {
|
|||||||
let chain = self.chain.read();
|
let chain = self.chain.read();
|
||||||
// Check the block isn't so old we won't be able to enact it.
|
// Check the block isn't so old we won't be able to enact it.
|
||||||
let best_block_number = chain.best_block_number();
|
let best_block_number = chain.best_block_number();
|
||||||
if best_block_number >= self.history && header.number() <= best_block_number - self.history {
|
if self.pruning_info().earliest_state > header.number() {
|
||||||
warn!(target: "client", "Block import failed for #{} ({})\nBlock is ancient (current best block: #{}).", header.number(), header.hash(), best_block_number);
|
warn!(target: "client", "Block import failed for #{} ({})\nBlock is ancient (current best block: #{}).", header.number(), header.hash(), best_block_number);
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
@@ -375,10 +375,14 @@ impl Client {
|
|||||||
let db = self.state_db.lock().boxed_clone_canon(header.parent_hash());
|
let db = self.state_db.lock().boxed_clone_canon(header.parent_hash());
|
||||||
|
|
||||||
let enact_result = enact_verified(block, engine, self.tracedb.read().tracing_enabled(), db, &parent, last_hashes, self.factories.clone());
|
let enact_result = enact_verified(block, engine, self.tracedb.read().tracing_enabled(), db, &parent, last_hashes, self.factories.clone());
|
||||||
let locked_block = enact_result.map_err(|e| {
|
let mut locked_block = enact_result.map_err(|e| {
|
||||||
warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
if header.number() < self.engine().params().validate_receipts_transition && header.receipts_root() != locked_block.block().header().receipts_root() {
|
||||||
|
locked_block = locked_block.strip_receipts();
|
||||||
|
}
|
||||||
|
|
||||||
// Final Verification
|
// Final Verification
|
||||||
if let Err(e) = self.verifier.verify_block_final(header, locked_block.block().header()) {
|
if let Err(e) = self.verifier.verify_block_final(header, locked_block.block().header()) {
|
||||||
warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
||||||
@@ -673,7 +677,7 @@ impl Client {
|
|||||||
let db = self.state_db.lock().boxed_clone();
|
let db = self.state_db.lock().boxed_clone();
|
||||||
|
|
||||||
// early exit for pruned blocks
|
// early exit for pruned blocks
|
||||||
if db.is_pruned() && self.chain.read().best_block_number() >= block_number + self.history {
|
if db.is_pruned() && self.pruning_info().earliest_state > block_number {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -774,7 +778,7 @@ impl Client {
|
|||||||
let best_block_number = self.chain_info().best_block_number;
|
let best_block_number = self.chain_info().best_block_number;
|
||||||
let block_number = self.block_number(at).ok_or(snapshot::Error::InvalidStartingBlock(at))?;
|
let block_number = self.block_number(at).ok_or(snapshot::Error::InvalidStartingBlock(at))?;
|
||||||
|
|
||||||
if best_block_number > self.history + block_number && db.is_pruned() {
|
if db.is_pruned() && self.pruning_info().earliest_state > block_number {
|
||||||
return Err(snapshot::Error::OldBlockPrunedDB.into());
|
return Err(snapshot::Error::OldBlockPrunedDB.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1445,7 +1449,7 @@ impl BlockChainClient for Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_contract(&self, address: Address, data: Bytes) -> Result<Bytes, String> {
|
fn call_contract(&self, block_id: BlockId, address: Address, data: Bytes) -> Result<Bytes, String> {
|
||||||
let from = Address::default();
|
let from = Address::default();
|
||||||
let transaction = Transaction {
|
let transaction = Transaction {
|
||||||
nonce: self.latest_nonce(&from),
|
nonce: self.latest_nonce(&from),
|
||||||
@@ -1456,7 +1460,7 @@ impl BlockChainClient for Client {
|
|||||||
data: data,
|
data: data,
|
||||||
}.fake_sign(from);
|
}.fake_sign(from);
|
||||||
|
|
||||||
self.call(&transaction, BlockId::Latest, Default::default())
|
self.call(&transaction, block_id, Default::default())
|
||||||
.map_err(|e| format!("{:?}", e))
|
.map_err(|e| format!("{:?}", e))
|
||||||
.map(|executed| {
|
.map(|executed| {
|
||||||
executed.output
|
executed.output
|
||||||
@@ -1528,6 +1532,33 @@ impl MiningBlockChainClient for Client {
|
|||||||
open_block
|
open_block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reopen_block(&self, block: ClosedBlock) -> OpenBlock {
|
||||||
|
let engine = &*self.engine;
|
||||||
|
let mut block = block.reopen(engine);
|
||||||
|
let max_uncles = engine.maximum_uncle_count();
|
||||||
|
if block.uncles().len() < max_uncles {
|
||||||
|
let chain = self.chain.read();
|
||||||
|
let h = chain.best_block_hash();
|
||||||
|
// Add new uncles
|
||||||
|
let uncles = chain
|
||||||
|
.find_uncle_hashes(&h, engine.maximum_uncle_age())
|
||||||
|
.unwrap_or_else(Vec::new);
|
||||||
|
|
||||||
|
for h in uncles {
|
||||||
|
if !block.uncles().iter().any(|header| header.hash() == h) {
|
||||||
|
let uncle = chain.block_header(&h).expect("find_uncle_hashes only returns hashes for existing headers; qed");
|
||||||
|
block.push_uncle(uncle).expect("pushing up to maximum_uncle_count;
|
||||||
|
push_uncle is not ok only if more than maximum_uncle_count is pushed;
|
||||||
|
so all push_uncle are Ok;
|
||||||
|
qed");
|
||||||
|
if block.uncles().len() >= max_uncles { break }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
block
|
||||||
|
}
|
||||||
|
|
||||||
fn vm_factory(&self) -> &EvmFactory {
|
fn vm_factory(&self) -> &EvmFactory {
|
||||||
&self.factories.vm
|
&self.factories.vm
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ use types::mode::Mode;
|
|||||||
use types::pruning_info::PruningInfo;
|
use types::pruning_info::PruningInfo;
|
||||||
|
|
||||||
use verification::queue::QueueInfo;
|
use verification::queue::QueueInfo;
|
||||||
use block::{OpenBlock, SealedBlock};
|
use block::{OpenBlock, SealedBlock, ClosedBlock};
|
||||||
use executive::Executed;
|
use executive::Executed;
|
||||||
use error::CallError;
|
use error::CallError;
|
||||||
use trace::LocalizedTrace;
|
use trace::LocalizedTrace;
|
||||||
@@ -378,6 +378,10 @@ impl MiningBlockChainClient for TestBlockChainClient {
|
|||||||
open_block
|
open_block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reopen_block(&self, block: ClosedBlock) -> OpenBlock {
|
||||||
|
block.reopen(&*self.spec.engine)
|
||||||
|
}
|
||||||
|
|
||||||
fn vm_factory(&self) -> &EvmFactory {
|
fn vm_factory(&self) -> &EvmFactory {
|
||||||
&self.vm_factory
|
&self.vm_factory
|
||||||
}
|
}
|
||||||
@@ -731,7 +735,7 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_contract(&self, _address: Address, _data: Bytes) -> Result<Bytes, String> { Ok(vec![]) }
|
fn call_contract(&self, _id: BlockId, _address: Address, _data: Bytes) -> Result<Bytes, String> { Ok(vec![]) }
|
||||||
|
|
||||||
fn transact_contract(&self, address: Address, data: Bytes) -> Result<TransactionImportResult, EthcoreError> {
|
fn transact_contract(&self, address: Address, data: Bytes) -> Result<TransactionImportResult, EthcoreError> {
|
||||||
let transaction = Transaction {
|
let transaction = Transaction {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use std::collections::BTreeMap;
|
|||||||
use util::{U256, Address, H256, H2048, Bytes, Itertools};
|
use util::{U256, Address, H256, H2048, Bytes, Itertools};
|
||||||
use blockchain::TreeRoute;
|
use blockchain::TreeRoute;
|
||||||
use verification::queue::QueueInfo as BlockQueueInfo;
|
use verification::queue::QueueInfo as BlockQueueInfo;
|
||||||
use block::{OpenBlock, SealedBlock};
|
use block::{OpenBlock, SealedBlock, ClosedBlock};
|
||||||
use header::{BlockNumber};
|
use header::{BlockNumber};
|
||||||
use transaction::{LocalizedTransaction, PendingTransaction, SignedTransaction};
|
use transaction::{LocalizedTransaction, PendingTransaction, SignedTransaction};
|
||||||
use transaction_import::TransactionImportResult;
|
use transaction_import::TransactionImportResult;
|
||||||
@@ -254,7 +254,7 @@ pub trait BlockChainClient : Sync + Send {
|
|||||||
fn pruning_info(&self) -> PruningInfo;
|
fn pruning_info(&self) -> PruningInfo;
|
||||||
|
|
||||||
/// Like `call`, but with various defaults. Designed to be used for calling contracts.
|
/// Like `call`, but with various defaults. Designed to be used for calling contracts.
|
||||||
fn call_contract(&self, address: Address, data: Bytes) -> Result<Bytes, String>;
|
fn call_contract(&self, id: BlockId, address: Address, data: Bytes) -> Result<Bytes, String>;
|
||||||
|
|
||||||
/// Import a transaction: used for misbehaviour reporting.
|
/// Import a transaction: used for misbehaviour reporting.
|
||||||
fn transact_contract(&self, address: Address, data: Bytes) -> Result<TransactionImportResult, EthcoreError>;
|
fn transact_contract(&self, address: Address, data: Bytes) -> Result<TransactionImportResult, EthcoreError>;
|
||||||
@@ -277,6 +277,9 @@ pub trait MiningBlockChainClient: BlockChainClient {
|
|||||||
extra_data: Bytes
|
extra_data: Bytes
|
||||||
) -> OpenBlock;
|
) -> OpenBlock;
|
||||||
|
|
||||||
|
/// Reopens an OpenBlock and updates uncles.
|
||||||
|
fn reopen_block(&self, block: ClosedBlock) -> OpenBlock;
|
||||||
|
|
||||||
/// Returns EvmFactory.
|
/// Returns EvmFactory.
|
||||||
fn vm_factory(&self) -> &EvmFactory;
|
fn vm_factory(&self) -> &EvmFactory;
|
||||||
|
|
||||||
|
|||||||
@@ -27,12 +27,13 @@ use block::*;
|
|||||||
use spec::CommonParams;
|
use spec::CommonParams;
|
||||||
use engines::{Engine, Seal, EngineError};
|
use engines::{Engine, Seal, EngineError};
|
||||||
use header::Header;
|
use header::Header;
|
||||||
use error::{Error, BlockError};
|
use error::{Error, TransactionError, BlockError};
|
||||||
use evm::Schedule;
|
use evm::Schedule;
|
||||||
use ethjson;
|
use ethjson;
|
||||||
use io::{IoContext, IoHandler, TimerToken, IoService};
|
use io::{IoContext, IoHandler, TimerToken, IoService};
|
||||||
use env_info::EnvInfo;
|
use env_info::EnvInfo;
|
||||||
use builtin::Builtin;
|
use builtin::Builtin;
|
||||||
|
use transaction::UnverifiedTransaction;
|
||||||
use client::{Client, EngineClient};
|
use client::{Client, EngineClient};
|
||||||
use state::CleanupMode;
|
use state::CleanupMode;
|
||||||
use super::signer::EngineSigner;
|
use super::signer::EngineSigner;
|
||||||
@@ -53,6 +54,12 @@ pub struct AuthorityRoundParams {
|
|||||||
pub start_step: Option<u64>,
|
pub start_step: Option<u64>,
|
||||||
/// Valid validators.
|
/// Valid validators.
|
||||||
pub validators: ethjson::spec::ValidatorSet,
|
pub validators: ethjson::spec::ValidatorSet,
|
||||||
|
/// Chain score validation transition block.
|
||||||
|
pub validate_score_transition: u64,
|
||||||
|
/// Number of first block where EIP-155 rules are validated.
|
||||||
|
pub eip155_transition: u64,
|
||||||
|
/// Monotonic step validation transition block.
|
||||||
|
pub validate_step_transition: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
|
impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
|
||||||
@@ -64,6 +71,9 @@ impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
|
|||||||
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),
|
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),
|
||||||
|
validate_score_transition: p.validate_score_transition.map_or(0, Into::into),
|
||||||
|
eip155_transition: p.eip155_transition.map_or(0, Into::into),
|
||||||
|
validate_step_transition: p.validate_step_transition.map_or(0, Into::into),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -82,7 +92,12 @@ pub struct AuthorityRound {
|
|||||||
proposed: AtomicBool,
|
proposed: AtomicBool,
|
||||||
client: RwLock<Option<Weak<EngineClient>>>,
|
client: RwLock<Option<Weak<EngineClient>>>,
|
||||||
signer: EngineSigner,
|
signer: EngineSigner,
|
||||||
validators: Box<ValidatorSet + Send + Sync>,
|
validators: Box<ValidatorSet>,
|
||||||
|
/// Is this Engine just for testing (prevents step calibration).
|
||||||
|
calibrate_step: bool,
|
||||||
|
validate_score_transition: u64,
|
||||||
|
eip155_transition: u64,
|
||||||
|
validate_step_transition: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header_step(header: &Header) -> Result<usize, ::rlp::DecoderError> {
|
fn header_step(header: &Header) -> Result<usize, ::rlp::DecoderError> {
|
||||||
@@ -122,6 +137,10 @@ impl AuthorityRound {
|
|||||||
client: RwLock::new(None),
|
client: RwLock::new(None),
|
||||||
signer: Default::default(),
|
signer: Default::default(),
|
||||||
validators: new_validator_set(our_params.validators),
|
validators: new_validator_set(our_params.validators),
|
||||||
|
calibrate_step: our_params.start_step.is_none(),
|
||||||
|
validate_score_transition: our_params.validate_score_transition,
|
||||||
|
eip155_transition: our_params.eip155_transition,
|
||||||
|
validate_step_transition: our_params.validate_step_transition,
|
||||||
});
|
});
|
||||||
// Do not initialize timeouts for tests.
|
// Do not initialize timeouts for tests.
|
||||||
if should_timeout {
|
if should_timeout {
|
||||||
@@ -131,6 +150,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);
|
||||||
@@ -141,12 +166,22 @@ impl AuthorityRound {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn step_proposer(&self, step: usize) -> Address {
|
fn step_proposer(&self, bh: &H256, step: usize) -> Address {
|
||||||
self.validators.get(step)
|
self.validators.get(bh, step)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_step_proposer(&self, step: usize, address: &Address) -> bool {
|
fn is_step_proposer(&self, bh: &H256, step: usize, address: &Address) -> bool {
|
||||||
self.step_proposer(step) == *address
|
self.step_proposer(bh, 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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,9 +251,8 @@ impl Engine for AuthorityRound {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) {
|
fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) {
|
||||||
// Chain scoring: total weight is sqrt(U256::max_value())*height - step
|
// Chain scoring: weak height scoring, backported for compatibility.
|
||||||
let new_difficulty = U256::from(U128::max_value()) + header_step(parent).expect("Header has been verified; qed").into() - self.step.load(AtomicOrdering::SeqCst).into();
|
header.set_difficulty(parent.difficulty().clone());
|
||||||
header.set_difficulty(new_difficulty);
|
|
||||||
header.set_gas_limit({
|
header.set_gas_limit({
|
||||||
let gas_limit = parent.gas_limit().clone();
|
let gas_limit = parent.gas_limit().clone();
|
||||||
let bound_divisor = self.gas_limit_bound_divisor;
|
let bound_divisor = self.gas_limit_bound_divisor;
|
||||||
@@ -231,7 +265,7 @@ impl Engine for AuthorityRound {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn seals_internally(&self) -> Option<bool> {
|
fn seals_internally(&self) -> Option<bool> {
|
||||||
Some(self.validators.contains(&self.signer.address()))
|
Some(self.signer.address() != Address::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to seal the block internally.
|
/// Attempt to seal the block internally.
|
||||||
@@ -242,7 +276,7 @@ impl Engine for AuthorityRound {
|
|||||||
if self.proposed.load(AtomicOrdering::SeqCst) { return Seal::None; }
|
if self.proposed.load(AtomicOrdering::SeqCst) { return Seal::None; }
|
||||||
let header = block.header();
|
let header = block.header();
|
||||||
let step = self.step.load(AtomicOrdering::SeqCst);
|
let step = self.step.load(AtomicOrdering::SeqCst);
|
||||||
if self.is_step_proposer(step, header.author()) {
|
if self.is_step_proposer(header.parent_hash(), step, header.author()) {
|
||||||
if let Ok(signature) = self.signer.sign(header.bare_hash()) {
|
if let Ok(signature) = self.signer.sign(header.bare_hash()) {
|
||||||
trace!(target: "engine", "generate_seal: Issuing a block for step {}.", step);
|
trace!(target: "engine", "generate_seal: Issuing a block for step {}.", step);
|
||||||
self.proposed.store(true, AtomicOrdering::SeqCst);
|
self.proposed.store(true, AtomicOrdering::SeqCst);
|
||||||
@@ -276,40 +310,47 @@ impl Engine for AuthorityRound {
|
|||||||
Err(From::from(BlockError::InvalidSealArity(
|
Err(From::from(BlockError::InvalidSealArity(
|
||||||
Mismatch { expected: self.seal_fields(), found: header.seal().len() }
|
Mismatch { expected: self.seal_fields(), found: header.seal().len() }
|
||||||
)))
|
)))
|
||||||
|
} else if header.number() >= self.validate_score_transition && *header.difficulty() >= U256::from(U128::max_value()) {
|
||||||
|
Err(From::from(BlockError::DifficultyOutOfBounds(
|
||||||
|
OutOfBounds { min: None, max: Some(U256::from(U128::max_value())), found: *header.difficulty() }
|
||||||
|
)))
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the signature belongs to the correct proposer.
|
fn verify_block_unordered(&self, _header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
|
||||||
fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
|
Ok(())
|
||||||
let header_step = header_step(header)?;
|
}
|
||||||
|
|
||||||
|
/// Do the validator and gas limit validation.
|
||||||
|
fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
|
||||||
|
let 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(step) {
|
||||||
let proposer_signature = header_signature(header)?;
|
|
||||||
let correct_proposer = self.step_proposer(header_step);
|
|
||||||
if verify_address(&correct_proposer, &proposer_signature, &header.bare_hash())? {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
trace!(target: "engine", "verify_block_unordered: bad proposer for step: {}", header_step);
|
|
||||||
Err(EngineError::NotProposer(Mismatch { expected: correct_proposer, found: header.author().clone() }))?
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
trace!(target: "engine", "verify_block_unordered: block from the future");
|
trace!(target: "engine", "verify_block_unordered: block from the future");
|
||||||
self.validators.report_benign(header.author());
|
self.validators.report_benign(header.author());
|
||||||
Err(BlockError::InvalidSeal)?
|
Err(BlockError::InvalidSeal)?
|
||||||
|
} else {
|
||||||
|
// Check if the signature belongs to a validator, can depend on parent state.
|
||||||
|
let proposer_signature = header_signature(header)?;
|
||||||
|
let correct_proposer = self.step_proposer(header.parent_hash(), step);
|
||||||
|
if !verify_address(&correct_proposer, &proposer_signature, &header.bare_hash())? {
|
||||||
|
trace!(target: "engine", "verify_block_unordered: bad proposer for step: {}", step);
|
||||||
|
Err(EngineError::NotProposer(Mismatch { expected: correct_proposer, found: header.author().clone() }))?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
|
// Do not calculate difficulty for genesis blocks.
|
||||||
if header.number() == 0 {
|
if header.number() == 0 {
|
||||||
return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() })));
|
return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() })));
|
||||||
}
|
}
|
||||||
|
|
||||||
let step = header_step(header)?;
|
|
||||||
// Check if parent is from a previous step.
|
// Check if parent is from a previous step.
|
||||||
if step == header_step(parent)? {
|
let parent_step = header_step(parent)?;
|
||||||
trace!(target: "engine", "Multiple blocks proposed for step {}.", step);
|
if step == parent_step
|
||||||
|
|| (header.number() >= self.validate_step_transition && step <= parent_step) {
|
||||||
|
trace!(target: "engine", "Multiple blocks proposed for step {}.", parent_step);
|
||||||
self.validators.report_malicious(header.author());
|
self.validators.report_malicious(header.author());
|
||||||
Err(EngineError::DoubleVote(header.author().clone()))?;
|
Err(EngineError::DoubleVote(header.author().clone()))?;
|
||||||
}
|
}
|
||||||
@@ -323,6 +364,18 @@ impl Engine for AuthorityRound {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn verify_transaction_basic(&self, t: &UnverifiedTransaction, header: &Header) -> result::Result<(), Error> {
|
||||||
|
t.check_low_s()?;
|
||||||
|
|
||||||
|
if let Some(n) = t.network_id() {
|
||||||
|
if header.number() >= self.eip155_transition && n != self.params().chain_id {
|
||||||
|
return Err(TransactionError::InvalidNetworkId.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn register_client(&self, client: Weak<Client>) {
|
fn register_client(&self, client: Weak<Client>) {
|
||||||
*self.client.write() = Some(client.clone());
|
*self.client.write() = Some(client.clone());
|
||||||
self.validators.register_contract(client);
|
self.validators.register_contract(client);
|
||||||
@@ -394,7 +447,7 @@ mod tests {
|
|||||||
let mut header: Header = Header::default();
|
let mut header: Header = Header::default();
|
||||||
header.set_seal(vec![encode(&H520::default()).to_vec()]);
|
header.set_seal(vec![encode(&H520::default()).to_vec()]);
|
||||||
|
|
||||||
let verify_result = engine.verify_block_unordered(&header, None);
|
let verify_result = engine.verify_block_family(&header, &Default::default(), None);
|
||||||
assert!(verify_result.is_err());
|
assert!(verify_result.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,10 +485,14 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn proposer_switching() {
|
fn proposer_switching() {
|
||||||
let mut header: Header = Header::default();
|
|
||||||
let tap = AccountProvider::transient_provider();
|
let tap = AccountProvider::transient_provider();
|
||||||
let addr = tap.insert_account(Secret::from_slice(&"0".sha3()).unwrap(), "0").unwrap();
|
let addr = tap.insert_account(Secret::from_slice(&"0".sha3()).unwrap(), "0").unwrap();
|
||||||
|
let mut parent_header: Header = Header::default();
|
||||||
|
parent_header.set_seal(vec![encode(&0usize).to_vec()]);
|
||||||
|
parent_header.set_gas_limit(U256::from_str("222222").unwrap());
|
||||||
|
let mut header: Header = Header::default();
|
||||||
|
header.set_number(1);
|
||||||
|
header.set_gas_limit(U256::from_str("222222").unwrap());
|
||||||
header.set_author(addr);
|
header.set_author(addr);
|
||||||
|
|
||||||
let engine = Spec::new_test_round().engine;
|
let engine = Spec::new_test_round().engine;
|
||||||
@@ -444,17 +501,22 @@ mod tests {
|
|||||||
// Two validators.
|
// Two validators.
|
||||||
// Spec starts with step 2.
|
// Spec starts with step 2.
|
||||||
header.set_seal(vec![encode(&2usize).to_vec(), encode(&(&*signature as &[u8])).to_vec()]);
|
header.set_seal(vec![encode(&2usize).to_vec(), encode(&(&*signature as &[u8])).to_vec()]);
|
||||||
assert!(engine.verify_block_seal(&header).is_err());
|
assert!(engine.verify_block_family(&header, &parent_header, None).is_err());
|
||||||
header.set_seal(vec![encode(&1usize).to_vec(), encode(&(&*signature as &[u8])).to_vec()]);
|
header.set_seal(vec![encode(&1usize).to_vec(), encode(&(&*signature as &[u8])).to_vec()]);
|
||||||
assert!(engine.verify_block_seal(&header).is_ok());
|
assert!(engine.verify_block_family(&header, &parent_header, None).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rejects_future_block() {
|
fn rejects_future_block() {
|
||||||
let mut header: Header = Header::default();
|
|
||||||
let tap = AccountProvider::transient_provider();
|
let tap = AccountProvider::transient_provider();
|
||||||
let addr = tap.insert_account(Secret::from_slice(&"0".sha3()).unwrap(), "0").unwrap();
|
let addr = tap.insert_account(Secret::from_slice(&"0".sha3()).unwrap(), "0").unwrap();
|
||||||
|
|
||||||
|
let mut parent_header: Header = Header::default();
|
||||||
|
parent_header.set_seal(vec![encode(&0usize).to_vec()]);
|
||||||
|
parent_header.set_gas_limit(U256::from_str("222222").unwrap());
|
||||||
|
let mut header: Header = Header::default();
|
||||||
|
header.set_number(1);
|
||||||
|
header.set_gas_limit(U256::from_str("222222").unwrap());
|
||||||
header.set_author(addr);
|
header.set_author(addr);
|
||||||
|
|
||||||
let engine = Spec::new_test_round().engine;
|
let engine = Spec::new_test_round().engine;
|
||||||
@@ -463,8 +525,8 @@ mod tests {
|
|||||||
// Two validators.
|
// Two validators.
|
||||||
// Spec starts with step 2.
|
// Spec starts with step 2.
|
||||||
header.set_seal(vec![encode(&1usize).to_vec(), encode(&(&*signature as &[u8])).to_vec()]);
|
header.set_seal(vec![encode(&1usize).to_vec(), encode(&(&*signature as &[u8])).to_vec()]);
|
||||||
assert!(engine.verify_block_seal(&header).is_ok());
|
assert!(engine.verify_block_family(&header, &parent_header, None).is_ok());
|
||||||
header.set_seal(vec![encode(&5usize).to_vec(), encode(&(&*signature as &[u8])).to_vec()]);
|
header.set_seal(vec![encode(&5usize).to_vec(), encode(&(&*signature as &[u8])).to_vec()]);
|
||||||
assert!(engine.verify_block_seal(&header).is_err());
|
assert!(engine.verify_block_family(&header, &parent_header, None).is_err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ pub struct BasicAuthority {
|
|||||||
gas_limit_bound_divisor: U256,
|
gas_limit_bound_divisor: U256,
|
||||||
builtins: BTreeMap<Address, Builtin>,
|
builtins: BTreeMap<Address, Builtin>,
|
||||||
signer: EngineSigner,
|
signer: EngineSigner,
|
||||||
validators: Box<ValidatorSet + Send + Sync>,
|
validators: Box<ValidatorSet>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BasicAuthority {
|
impl BasicAuthority {
|
||||||
@@ -104,14 +104,14 @@ impl Engine for BasicAuthority {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn seals_internally(&self) -> Option<bool> {
|
fn seals_internally(&self) -> Option<bool> {
|
||||||
Some(self.validators.contains(&self.signer.address()))
|
Some(self.signer.address() != Address::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to seal the block internally.
|
/// Attempt to seal the block internally.
|
||||||
fn generate_seal(&self, block: &ExecutedBlock) -> Seal {
|
fn generate_seal(&self, block: &ExecutedBlock) -> Seal {
|
||||||
let header = block.header();
|
let header = block.header();
|
||||||
let author = header.author();
|
let author = header.author();
|
||||||
if self.validators.contains(author) {
|
if self.validators.contains(header.parent_hash(), author) {
|
||||||
// account should be pernamently unlocked, otherwise sealing will fail
|
// account should be pernamently unlocked, otherwise sealing will fail
|
||||||
if let Ok(signature) = self.signer.sign(header.bare_hash()) {
|
if let Ok(signature) = self.signer.sign(header.bare_hash()) {
|
||||||
return Seal::Regular(vec![::rlp::encode(&(&H520::from(signature) as &[u8])).to_vec()]);
|
return Seal::Regular(vec![::rlp::encode(&(&H520::from(signature) as &[u8])).to_vec()]);
|
||||||
@@ -133,20 +133,20 @@ impl Engine for BasicAuthority {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
fn verify_block_unordered(&self, _header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
||||||
use rlp::{UntrustedRlp, View};
|
|
||||||
|
|
||||||
// check the signature is legit.
|
|
||||||
let sig = UntrustedRlp::new(&header.seal()[0]).as_val::<H520>()?;
|
|
||||||
let signer = public_to_address(&recover(&sig.into(), &header.bare_hash())?);
|
|
||||||
if !self.validators.contains(&signer) {
|
|
||||||
return Err(BlockError::InvalidSeal)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
||||||
// we should not calculate difficulty for genesis blocks
|
use rlp::{UntrustedRlp, View};
|
||||||
|
// Check if the signature belongs to a validator, can depend on parent state.
|
||||||
|
let sig = UntrustedRlp::new(&header.seal()[0]).as_val::<H520>()?;
|
||||||
|
let signer = public_to_address(&recover(&sig.into(), &header.bare_hash())?);
|
||||||
|
if !self.validators.contains(header.parent_hash(), &signer) {
|
||||||
|
return Err(BlockError::InvalidSeal)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not calculate difficulty for genesis blocks.
|
||||||
if header.number() == 0 {
|
if header.number() == 0 {
|
||||||
return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() })));
|
return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() })));
|
||||||
}
|
}
|
||||||
@@ -239,7 +239,7 @@ mod tests {
|
|||||||
let mut header: Header = Header::default();
|
let mut header: Header = Header::default();
|
||||||
header.set_seal(vec![::rlp::encode(&H520::default()).to_vec()]);
|
header.set_seal(vec![::rlp::encode(&H520::default()).to_vec()]);
|
||||||
|
|
||||||
let verify_result = engine.verify_block_unordered(&header, None);
|
let verify_result = engine.verify_block_family(&header, &Default::default(), None);
|
||||||
assert!(verify_result.is_err());
|
assert!(verify_result.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ use account_provider::AccountProvider;
|
|||||||
use block::ExecutedBlock;
|
use block::ExecutedBlock;
|
||||||
use builtin::Builtin;
|
use builtin::Builtin;
|
||||||
use env_info::EnvInfo;
|
use env_info::EnvInfo;
|
||||||
use error::Error;
|
use error::{Error, TransactionError};
|
||||||
use spec::CommonParams;
|
use spec::CommonParams;
|
||||||
use evm::Schedule;
|
use evm::Schedule;
|
||||||
use header::Header;
|
use header::Header;
|
||||||
@@ -157,6 +157,13 @@ pub trait Engine : Sync + Send {
|
|||||||
// TODO: consider including State in the params.
|
// TODO: consider including State in the params.
|
||||||
fn verify_transaction_basic(&self, t: &UnverifiedTransaction, _header: &Header) -> Result<(), Error> {
|
fn verify_transaction_basic(&self, t: &UnverifiedTransaction, _header: &Header) -> Result<(), Error> {
|
||||||
t.check_low_s()?;
|
t.check_low_s()?;
|
||||||
|
|
||||||
|
if let Some(n) = t.network_id() {
|
||||||
|
if n != self.params().chain_id {
|
||||||
|
return Err(TransactionError::InvalidNetworkId.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +173,9 @@ pub trait Engine : Sync + Send {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
|
|||||||
@@ -95,8 +95,10 @@ pub struct Tendermint {
|
|||||||
last_lock: AtomicUsize,
|
last_lock: AtomicUsize,
|
||||||
/// Bare hash of the proposed block, used for seal submission.
|
/// Bare hash of the proposed block, used for seal submission.
|
||||||
proposal: RwLock<Option<H256>>,
|
proposal: RwLock<Option<H256>>,
|
||||||
|
/// Hash of the proposal parent block.
|
||||||
|
proposal_parent: RwLock<H256>,
|
||||||
/// Set used to determine the current validators.
|
/// Set used to determine the current validators.
|
||||||
validators: Box<ValidatorSet + Send + Sync>,
|
validators: Box<ValidatorSet>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tendermint {
|
impl Tendermint {
|
||||||
@@ -114,11 +116,12 @@ impl Tendermint {
|
|||||||
height: AtomicUsize::new(1),
|
height: AtomicUsize::new(1),
|
||||||
view: AtomicUsize::new(0),
|
view: AtomicUsize::new(0),
|
||||||
step: RwLock::new(Step::Propose),
|
step: RwLock::new(Step::Propose),
|
||||||
votes: VoteCollector::default(),
|
votes: Default::default(),
|
||||||
signer: Default::default(),
|
signer: Default::default(),
|
||||||
lock_change: RwLock::new(None),
|
lock_change: RwLock::new(None),
|
||||||
last_lock: AtomicUsize::new(0),
|
last_lock: AtomicUsize::new(0),
|
||||||
proposal: RwLock::new(None),
|
proposal: RwLock::new(None),
|
||||||
|
proposal_parent: Default::default(),
|
||||||
validators: new_validator_set(our_params.validators),
|
validators: new_validator_set(our_params.validators),
|
||||||
});
|
});
|
||||||
let handler = TransitionHandler::new(Arc::downgrade(&engine) as Weak<Engine>, Box::new(our_params.timeouts));
|
let handler = TransitionHandler::new(Arc::downgrade(&engine) as Weak<Engine>, Box::new(our_params.timeouts));
|
||||||
@@ -232,7 +235,7 @@ impl Tendermint {
|
|||||||
let height = self.height.load(AtomicOrdering::SeqCst);
|
let height = self.height.load(AtomicOrdering::SeqCst);
|
||||||
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_signer_proposer() {
|
if self.is_signer_proposer(&*self.proposal_parent.read()) {
|
||||||
let proposal_step = VoteStep::new(height, view, Step::Propose);
|
let proposal_step = VoteStep::new(height, view, Step::Propose);
|
||||||
let precommit_step = VoteStep::new(proposal_step.height, proposal_step.view, Step::Precommit);
|
let precommit_step = VoteStep::new(proposal_step.height, proposal_step.view, Step::Precommit);
|
||||||
if let Some(seal) = self.votes.seal_signatures(proposal_step, precommit_step, &block_hash) {
|
if let Some(seal) = self.votes.seal_signatures(proposal_step, precommit_step, &block_hash) {
|
||||||
@@ -254,23 +257,23 @@ impl Tendermint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_authority(&self, address: &Address) -> bool {
|
fn is_authority(&self, address: &Address) -> bool {
|
||||||
self.validators.contains(address)
|
self.validators.contains(&*self.proposal_parent.read(), address)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_above_threshold(&self, n: usize) -> bool {
|
fn is_above_threshold(&self, n: usize) -> bool {
|
||||||
n > self.validators.count() * 2/3
|
n > self.validators.count(&*self.proposal_parent.read()) * 2/3
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find the designated for the given view.
|
/// Find the designated for the given view.
|
||||||
fn view_proposer(&self, height: Height, view: View) -> Address {
|
fn view_proposer(&self, bh: &H256, height: Height, view: View) -> Address {
|
||||||
let proposer_nonce = height + view;
|
let proposer_nonce = height + view;
|
||||||
trace!(target: "engine", "Proposer nonce: {}", proposer_nonce);
|
trace!(target: "engine", "Proposer nonce: {}", proposer_nonce);
|
||||||
self.validators.get(proposer_nonce)
|
self.validators.get(bh, proposer_nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if address is a proposer for given view.
|
/// Check if address is a proposer for given view.
|
||||||
fn is_view_proposer(&self, height: Height, view: View, address: &Address) -> Result<(), EngineError> {
|
fn is_view_proposer(&self, bh: &H256, height: Height, view: View, address: &Address) -> Result<(), EngineError> {
|
||||||
let proposer = self.view_proposer(height, view);
|
let proposer = self.view_proposer(bh, height, view);
|
||||||
if proposer == *address {
|
if proposer == *address {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
@@ -279,8 +282,8 @@ impl Tendermint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check if current signer is the current proposer.
|
/// Check if current signer is the current proposer.
|
||||||
fn is_signer_proposer(&self) -> bool {
|
fn is_signer_proposer(&self, bh: &H256) -> bool {
|
||||||
let proposer = self.view_proposer(self.height.load(AtomicOrdering::SeqCst), self.view.load(AtomicOrdering::SeqCst));
|
let proposer = self.view_proposer(bh, self.height.load(AtomicOrdering::SeqCst), self.view.load(AtomicOrdering::SeqCst));
|
||||||
self.signer.is_address(&proposer)
|
self.signer.is_address(&proposer)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,7 +422,7 @@ impl Engine for Tendermint {
|
|||||||
|
|
||||||
/// Should this node participate.
|
/// Should this node participate.
|
||||||
fn seals_internally(&self) -> Option<bool> {
|
fn seals_internally(&self) -> Option<bool> {
|
||||||
Some(self.is_authority(&self.signer.address()))
|
Some(self.signer.address() != Address::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to seal generate a proposal seal.
|
/// Attempt to seal generate a proposal seal.
|
||||||
@@ -427,7 +430,7 @@ impl Engine for Tendermint {
|
|||||||
let header = block.header();
|
let header = block.header();
|
||||||
let author = header.author();
|
let author = header.author();
|
||||||
// Only proposer can generate seal if None was generated.
|
// Only proposer can generate seal if None was generated.
|
||||||
if !self.is_signer_proposer() || self.proposal.read().is_some() {
|
if !self.is_signer_proposer(header.parent_hash()) || self.proposal.read().is_some() {
|
||||||
return Seal::None;
|
return Seal::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -441,6 +444,7 @@ impl Engine for Tendermint {
|
|||||||
self.votes.vote(ConsensusMessage::new(signature, height, view, Step::Propose, bh), author);
|
self.votes.vote(ConsensusMessage::new(signature, height, view, Step::Propose, bh), author);
|
||||||
// Remember proposal for later seal submission.
|
// Remember proposal for later seal submission.
|
||||||
*self.proposal.write() = bh;
|
*self.proposal.write() = bh;
|
||||||
|
*self.proposal_parent.write() = header.parent_hash().clone();
|
||||||
Seal::Proposal(vec![
|
Seal::Proposal(vec![
|
||||||
::rlp::encode(&view).to_vec(),
|
::rlp::encode(&view).to_vec(),
|
||||||
::rlp::encode(&signature).to_vec(),
|
::rlp::encode(&signature).to_vec(),
|
||||||
@@ -505,7 +509,12 @@ impl Engine for Tendermint {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
|
fn verify_block_unordered(&self, _header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verify validators and gas limit.
|
||||||
|
fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
|
||||||
let proposal = ConsensusMessage::new_proposal(header)?;
|
let proposal = ConsensusMessage::new_proposal(header)?;
|
||||||
let proposer = proposal.verify()?;
|
let proposer = proposal.verify()?;
|
||||||
if !self.is_authority(&proposer) {
|
if !self.is_authority(&proposer) {
|
||||||
@@ -522,7 +531,7 @@ impl Engine for Tendermint {
|
|||||||
Some(a) => a,
|
Some(a) => a,
|
||||||
None => public_to_address(&recover(&precommit.signature.into(), &precommit_hash)?),
|
None => public_to_address(&recover(&precommit.signature.into(), &precommit_hash)?),
|
||||||
};
|
};
|
||||||
if !self.validators.contains(&address) {
|
if !self.validators.contains(header.parent_hash(), &address) {
|
||||||
Err(EngineError::NotAuthorized(address.to_owned()))?
|
Err(EngineError::NotAuthorized(address.to_owned()))?
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -545,12 +554,9 @@ impl Engine for Tendermint {
|
|||||||
found: signatures_len
|
found: signatures_len
|
||||||
}))?;
|
}))?;
|
||||||
}
|
}
|
||||||
self.is_view_proposer(proposal.vote_step.height, proposal.vote_step.view, &proposer)?;
|
self.is_view_proposer(header.parent_hash(), proposal.vote_step.height, proposal.vote_step.view, &proposer)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
|
|
||||||
if header.number() == 0 {
|
if header.number() == 0 {
|
||||||
Err(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() }))?;
|
Err(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() }))?;
|
||||||
}
|
}
|
||||||
@@ -595,6 +601,7 @@ impl Engine for Tendermint {
|
|||||||
debug!(target: "engine", "Received a new proposal {:?} from {}.", proposal.vote_step, proposer);
|
debug!(target: "engine", "Received a new proposal {:?} from {}.", proposal.vote_step, proposer);
|
||||||
if self.is_view(&proposal) {
|
if self.is_view(&proposal) {
|
||||||
*self.proposal.write() = proposal.block_hash.clone();
|
*self.proposal.write() = proposal.block_hash.clone();
|
||||||
|
*self.proposal_parent.write() = header.parent_hash().clone();
|
||||||
}
|
}
|
||||||
self.votes.vote(proposal, &proposer);
|
self.votes.vote(proposal, &proposer);
|
||||||
true
|
true
|
||||||
@@ -607,7 +614,7 @@ impl Engine for Tendermint {
|
|||||||
trace!(target: "engine", "Propose timeout.");
|
trace!(target: "engine", "Propose timeout.");
|
||||||
if self.proposal.read().is_none() {
|
if self.proposal.read().is_none() {
|
||||||
// Report the proposer if no proposal was received.
|
// Report the proposer if no proposal was received.
|
||||||
let current_proposer = self.view_proposer(self.height.load(AtomicOrdering::SeqCst), self.view.load(AtomicOrdering::SeqCst));
|
let current_proposer = self.view_proposer(&*self.proposal_parent.read(), self.height.load(AtomicOrdering::SeqCst), self.view.load(AtomicOrdering::SeqCst));
|
||||||
self.validators.report_benign(¤t_proposer);
|
self.validators.report_benign(¤t_proposer);
|
||||||
}
|
}
|
||||||
Step::Prevote
|
Step::Prevote
|
||||||
@@ -765,20 +772,25 @@ mod tests {
|
|||||||
let (spec, tap) = setup();
|
let (spec, tap) = setup();
|
||||||
let engine = spec.engine;
|
let engine = spec.engine;
|
||||||
|
|
||||||
let mut header = Header::default();
|
let mut parent_header: Header = Header::default();
|
||||||
let validator = insert_and_unlock(&tap, "0");
|
parent_header.set_gas_limit(U256::from_str("222222").unwrap());
|
||||||
header.set_author(validator);
|
|
||||||
let seal = proposal_seal(&tap, &header, 0);
|
|
||||||
header.set_seal(seal);
|
|
||||||
// Good proposer.
|
|
||||||
assert!(engine.verify_block_unordered(&header.clone(), None).is_ok());
|
|
||||||
|
|
||||||
|
let mut header = Header::default();
|
||||||
|
header.set_number(1);
|
||||||
|
header.set_gas_limit(U256::from_str("222222").unwrap());
|
||||||
let validator = insert_and_unlock(&tap, "1");
|
let validator = insert_and_unlock(&tap, "1");
|
||||||
header.set_author(validator);
|
header.set_author(validator);
|
||||||
let seal = proposal_seal(&tap, &header, 0);
|
let seal = proposal_seal(&tap, &header, 0);
|
||||||
header.set_seal(seal);
|
header.set_seal(seal);
|
||||||
|
// Good proposer.
|
||||||
|
assert!(engine.verify_block_family(&header, &parent_header, None).is_ok());
|
||||||
|
|
||||||
|
let validator = insert_and_unlock(&tap, "0");
|
||||||
|
header.set_author(validator);
|
||||||
|
let seal = proposal_seal(&tap, &header, 0);
|
||||||
|
header.set_seal(seal);
|
||||||
// Bad proposer.
|
// Bad proposer.
|
||||||
match engine.verify_block_unordered(&header, None) {
|
match engine.verify_block_family(&header, &parent_header, None) {
|
||||||
Err(Error::Engine(EngineError::NotProposer(_))) => {},
|
Err(Error::Engine(EngineError::NotProposer(_))) => {},
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
@@ -788,7 +800,7 @@ mod tests {
|
|||||||
let seal = proposal_seal(&tap, &header, 0);
|
let seal = proposal_seal(&tap, &header, 0);
|
||||||
header.set_seal(seal);
|
header.set_seal(seal);
|
||||||
// Not authority.
|
// Not authority.
|
||||||
match engine.verify_block_unordered(&header, None) {
|
match engine.verify_block_family(&header, &parent_header, None) {
|
||||||
Err(Error::Engine(EngineError::NotAuthorized(_))) => {},
|
Err(Error::Engine(EngineError::NotAuthorized(_))) => {},
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
};
|
};
|
||||||
@@ -800,19 +812,24 @@ mod tests {
|
|||||||
let (spec, tap) = setup();
|
let (spec, tap) = setup();
|
||||||
let engine = spec.engine;
|
let engine = spec.engine;
|
||||||
|
|
||||||
|
let mut parent_header: Header = Header::default();
|
||||||
|
parent_header.set_gas_limit(U256::from_str("222222").unwrap());
|
||||||
|
|
||||||
let mut header = Header::default();
|
let mut header = Header::default();
|
||||||
|
header.set_number(2);
|
||||||
|
header.set_gas_limit(U256::from_str("222222").unwrap());
|
||||||
let proposer = insert_and_unlock(&tap, "1");
|
let proposer = insert_and_unlock(&tap, "1");
|
||||||
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(&VoteStep::new(0, 0, Step::Precommit), Some(header.bare_hash()));
|
let vote_info = message_info_rlp(&VoteStep::new(2, 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();
|
||||||
header.set_seal(seal.clone());
|
header.set_seal(seal.clone());
|
||||||
|
|
||||||
// One good signature is not enough.
|
// One good signature is not enough.
|
||||||
match engine.verify_block_unordered(&header, None) {
|
match engine.verify_block_family(&header, &parent_header, None) {
|
||||||
Err(Error::Engine(EngineError::BadSealFieldSize(_))) => {},
|
Err(Error::Engine(EngineError::BadSealFieldSize(_))) => {},
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
@@ -823,7 +840,7 @@ mod tests {
|
|||||||
seal[2] = ::rlp::encode(&vec![H520::from(signature1.clone()), H520::from(signature0.clone())]).to_vec();
|
seal[2] = ::rlp::encode(&vec![H520::from(signature1.clone()), H520::from(signature0.clone())]).to_vec();
|
||||||
header.set_seal(seal.clone());
|
header.set_seal(seal.clone());
|
||||||
|
|
||||||
assert!(engine.verify_block_unordered(&header, None).is_ok());
|
assert!(engine.verify_block_family(&header, &parent_header, None).is_ok());
|
||||||
|
|
||||||
let bad_voter = insert_and_unlock(&tap, "101");
|
let bad_voter = insert_and_unlock(&tap, "101");
|
||||||
let bad_signature = tap.sign(bad_voter, None, vote_info.sha3()).unwrap();
|
let bad_signature = tap.sign(bad_voter, None, vote_info.sha3()).unwrap();
|
||||||
@@ -832,7 +849,7 @@ mod tests {
|
|||||||
header.set_seal(seal);
|
header.set_seal(seal);
|
||||||
|
|
||||||
// One good and one bad signature.
|
// One good and one bad signature.
|
||||||
match engine.verify_block_unordered(&header, None) {
|
match engine.verify_block_family(&header, &parent_header, None) {
|
||||||
Err(Error::Engine(EngineError::NotAuthorized(_))) => {},
|
Err(Error::Engine(EngineError::NotAuthorized(_))) => {},
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,30 +26,30 @@ use super::safe_contract::ValidatorSafeContract;
|
|||||||
/// The validator contract should have the following interface:
|
/// The validator contract should have the following interface:
|
||||||
/// [{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"","type":"address[]"}],"payable":false,"type":"function"}]
|
/// [{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"","type":"address[]"}],"payable":false,"type":"function"}]
|
||||||
pub struct ValidatorContract {
|
pub struct ValidatorContract {
|
||||||
validators: Arc<ValidatorSafeContract>,
|
validators: ValidatorSafeContract,
|
||||||
provider: RwLock<Option<provider::Contract>>,
|
provider: RwLock<Option<provider::Contract>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ValidatorContract {
|
impl ValidatorContract {
|
||||||
pub fn new(contract_address: Address) -> Self {
|
pub fn new(contract_address: Address) -> Self {
|
||||||
ValidatorContract {
|
ValidatorContract {
|
||||||
validators: Arc::new(ValidatorSafeContract::new(contract_address)),
|
validators: ValidatorSafeContract::new(contract_address),
|
||||||
provider: RwLock::new(None),
|
provider: RwLock::new(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ValidatorSet for Arc<ValidatorContract> {
|
impl ValidatorSet for ValidatorContract {
|
||||||
fn contains(&self, address: &Address) -> bool {
|
fn contains(&self, bh: &H256, address: &Address) -> bool {
|
||||||
self.validators.contains(address)
|
self.validators.contains(bh, address)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self, nonce: usize) -> Address {
|
fn get(&self, bh: &H256, nonce: usize) -> Address {
|
||||||
self.validators.get(nonce)
|
self.validators.get(bh, nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count(&self) -> usize {
|
fn count(&self, bh: &H256) -> usize {
|
||||||
self.validators.count()
|
self.validators.count(bh)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_malicious(&self, address: &Address) {
|
fn report_malicious(&self, address: &Address) {
|
||||||
@@ -144,6 +144,7 @@ mod tests {
|
|||||||
use header::Header;
|
use header::Header;
|
||||||
use account_provider::AccountProvider;
|
use account_provider::AccountProvider;
|
||||||
use miner::MinerService;
|
use miner::MinerService;
|
||||||
|
use types::ids::BlockId;
|
||||||
use client::BlockChainClient;
|
use client::BlockChainClient;
|
||||||
use tests::helpers::generate_dummy_client_with_spec_and_accounts;
|
use tests::helpers::generate_dummy_client_with_spec_and_accounts;
|
||||||
use super::super::ValidatorSet;
|
use super::super::ValidatorSet;
|
||||||
@@ -154,8 +155,9 @@ mod tests {
|
|||||||
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_contract, None);
|
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_contract, None);
|
||||||
let vc = Arc::new(ValidatorContract::new(Address::from_str("0000000000000000000000000000000000000005").unwrap()));
|
let vc = Arc::new(ValidatorContract::new(Address::from_str("0000000000000000000000000000000000000005").unwrap()));
|
||||||
vc.register_contract(Arc::downgrade(&client));
|
vc.register_contract(Arc::downgrade(&client));
|
||||||
assert!(vc.contains(&Address::from_str("7d577a597b2742b498cb5cf0c26cdcd726d39e6e").unwrap()));
|
let last_hash = client.best_block_header().hash();
|
||||||
assert!(vc.contains(&Address::from_str("82a978b3f5962a5b0957d9ee9eef472ee55b42f1").unwrap()));
|
assert!(vc.contains(&last_hash, &Address::from_str("7d577a597b2742b498cb5cf0c26cdcd726d39e6e").unwrap()));
|
||||||
|
assert!(vc.contains(&last_hash, &Address::from_str("82a978b3f5962a5b0957d9ee9eef472ee55b42f1").unwrap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -171,18 +173,21 @@ mod tests {
|
|||||||
|
|
||||||
client.miner().set_engine_signer(v1, "".into()).unwrap();
|
client.miner().set_engine_signer(v1, "".into()).unwrap();
|
||||||
let mut header = Header::default();
|
let mut header = Header::default();
|
||||||
let seal = encode(&vec!(5u8)).to_vec();
|
let seal = vec![encode(&5u8).to_vec(), encode(&(&H520::default() as &[u8])).to_vec()];
|
||||||
header.set_seal(vec!(seal));
|
header.set_seal(seal);
|
||||||
header.set_author(v1);
|
header.set_author(v1);
|
||||||
header.set_number(1);
|
header.set_number(2);
|
||||||
|
header.set_parent_hash(client.chain_info().best_block_hash);
|
||||||
|
|
||||||
// `reportBenign` when the designated proposer releases block from the future (bad clock).
|
// `reportBenign` when the designated proposer releases block from the future (bad clock).
|
||||||
assert!(client.engine().verify_block_unordered(&header, None).is_err());
|
assert!(client.engine().verify_block_family(&header, &header, None).is_err());
|
||||||
// Seal a block.
|
// Seal a block.
|
||||||
client.engine().step();
|
client.engine().step();
|
||||||
assert_eq!(client.chain_info().best_block_number, 1);
|
assert_eq!(client.chain_info().best_block_number, 1);
|
||||||
// Check if the unresponsive validator is `disliked`.
|
// Check if the unresponsive validator is `disliked`.
|
||||||
assert_eq!(client.call_contract(validator_contract, "d8f2e0bf".from_hex().unwrap()).unwrap().to_hex(), "0000000000000000000000007d577a597b2742b498cb5cf0c26cdcd726d39e6e");
|
assert_eq!(client.call_contract(BlockId::Latest, validator_contract, "d8f2e0bf".from_hex().unwrap()).unwrap().to_hex(), "0000000000000000000000007d577a597b2742b498cb5cf0c26cdcd726d39e6e");
|
||||||
// Simulate a misbehaving validator by handling a double proposal.
|
// Simulate a misbehaving validator by handling a double proposal.
|
||||||
|
let header = client.best_block_header().decode();
|
||||||
assert!(client.engine().verify_block_family(&header, &header, None).is_err());
|
assert!(client.engine().verify_block_family(&header, &header, None).is_err());
|
||||||
// Seal a block.
|
// Seal a block.
|
||||||
client.engine().step();
|
client.engine().step();
|
||||||
|
|||||||
@@ -19,31 +19,36 @@
|
|||||||
mod simple_list;
|
mod simple_list;
|
||||||
mod safe_contract;
|
mod safe_contract;
|
||||||
mod contract;
|
mod contract;
|
||||||
|
mod multi;
|
||||||
|
|
||||||
use std::sync::Weak;
|
use std::sync::Weak;
|
||||||
use util::{Address, Arc};
|
use util::{Address, H256};
|
||||||
use ethjson::spec::ValidatorSet as ValidatorSpec;
|
use ethjson::spec::ValidatorSet as ValidatorSpec;
|
||||||
use client::Client;
|
use client::Client;
|
||||||
use self::simple_list::SimpleList;
|
use self::simple_list::SimpleList;
|
||||||
use self::contract::ValidatorContract;
|
use self::contract::ValidatorContract;
|
||||||
use self::safe_contract::ValidatorSafeContract;
|
use self::safe_contract::ValidatorSafeContract;
|
||||||
|
use self::multi::Multi;
|
||||||
|
|
||||||
/// Creates a validator set from spec.
|
/// Creates a validator set from spec.
|
||||||
pub fn new_validator_set(spec: ValidatorSpec) -> Box<ValidatorSet + Send + Sync> {
|
pub fn new_validator_set(spec: ValidatorSpec) -> Box<ValidatorSet> {
|
||||||
match spec {
|
match spec {
|
||||||
ValidatorSpec::List(list) => Box::new(SimpleList::new(list.into_iter().map(Into::into).collect())),
|
ValidatorSpec::List(list) => Box::new(SimpleList::new(list.into_iter().map(Into::into).collect())),
|
||||||
ValidatorSpec::SafeContract(address) => Box::new(Arc::new(ValidatorSafeContract::new(address.into()))),
|
ValidatorSpec::SafeContract(address) => Box::new(ValidatorSafeContract::new(address.into())),
|
||||||
ValidatorSpec::Contract(address) => Box::new(Arc::new(ValidatorContract::new(address.into()))),
|
ValidatorSpec::Contract(address) => Box::new(ValidatorContract::new(address.into())),
|
||||||
|
ValidatorSpec::Multi(sequence) => Box::new(
|
||||||
|
Multi::new(sequence.into_iter().map(|(block, set)| (block.into(), new_validator_set(set))).collect())
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ValidatorSet {
|
pub trait ValidatorSet: Send + Sync {
|
||||||
/// Checks if a given address is a validator.
|
/// Checks if a given address is a validator.
|
||||||
fn contains(&self, address: &Address) -> bool;
|
fn contains(&self, parent_block_hash: &H256, address: &Address) -> bool;
|
||||||
/// Draws an validator nonce modulo number of validators.
|
/// Draws an validator nonce modulo number of validators.
|
||||||
fn get(&self, nonce: usize) -> Address;
|
fn get(&self, parent_block_hash: &H256, nonce: usize) -> Address;
|
||||||
/// Returns the current number of validators.
|
/// Returns the current number of validators.
|
||||||
fn count(&self) -> usize;
|
fn count(&self, parent_block_hash: &H256) -> usize;
|
||||||
/// Notifies about malicious behaviour.
|
/// Notifies about malicious behaviour.
|
||||||
fn report_malicious(&self, _validator: &Address) {}
|
fn report_malicious(&self, _validator: &Address) {}
|
||||||
/// Notifies about benign misbehaviour.
|
/// Notifies about benign misbehaviour.
|
||||||
|
|||||||
158
ethcore/src/engines/validator_set/multi.rs
Normal file
158
ethcore/src/engines/validator_set/multi.rs
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
// Copyright 2015-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/>.
|
||||||
|
|
||||||
|
/// Validator set changing at fork blocks.
|
||||||
|
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::sync::Weak;
|
||||||
|
use util::{H256, Address, RwLock};
|
||||||
|
use ids::BlockId;
|
||||||
|
use header::BlockNumber;
|
||||||
|
use client::{Client, BlockChainClient};
|
||||||
|
use super::ValidatorSet;
|
||||||
|
|
||||||
|
type BlockNumberLookup = Box<Fn(&H256) -> Result<BlockNumber, String> + Send + Sync + 'static>;
|
||||||
|
|
||||||
|
pub struct Multi {
|
||||||
|
sets: BTreeMap<BlockNumber, Box<ValidatorSet>>,
|
||||||
|
block_number: RwLock<BlockNumberLookup>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Multi {
|
||||||
|
pub fn new(set_map: BTreeMap<BlockNumber, Box<ValidatorSet>>) -> Self {
|
||||||
|
assert!(set_map.get(&0u64).is_some(), "ValidatorSet has to be specified from block 0.");
|
||||||
|
Multi {
|
||||||
|
sets: set_map,
|
||||||
|
block_number: RwLock::new(Box::new(move |_| Err("No client!".into()))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn correct_set(&self, bh: &H256) -> Option<&Box<ValidatorSet>> {
|
||||||
|
match self
|
||||||
|
.block_number
|
||||||
|
.read()(bh)
|
||||||
|
.map(|parent_block| self
|
||||||
|
.sets
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.find(|&(block, _)| *block <= parent_block + 1)
|
||||||
|
.expect("constructor validation ensures that there is at least one validator set for block 0;
|
||||||
|
block 0 is less than any uint;
|
||||||
|
qed")
|
||||||
|
) {
|
||||||
|
Ok((block, set)) => {
|
||||||
|
trace!(target: "engine", "Multi ValidatorSet retrieved for block {}.", block);
|
||||||
|
Some(set)
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
debug!(target: "engine", "ValidatorSet could not be recovered: {}", e);
|
||||||
|
None
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ValidatorSet for Multi {
|
||||||
|
fn contains(&self, bh: &H256, address: &Address) -> bool {
|
||||||
|
self.correct_set(bh).map_or(false, |set| set.contains(bh, address))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(&self, bh: &H256, nonce: usize) -> Address {
|
||||||
|
self.correct_set(bh).map_or_else(Default::default, |set| set.get(bh, nonce))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count(&self, bh: &H256) -> usize {
|
||||||
|
self.correct_set(bh).map_or_else(usize::max_value, |set| set.count(bh))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn report_malicious(&self, validator: &Address) {
|
||||||
|
for set in self.sets.values() {
|
||||||
|
set.report_malicious(validator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn report_benign(&self, validator: &Address) {
|
||||||
|
for set in self.sets.values() {
|
||||||
|
set.report_benign(validator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_contract(&self, client: Weak<Client>) {
|
||||||
|
for set in self.sets.values() {
|
||||||
|
set.register_contract(client.clone());
|
||||||
|
}
|
||||||
|
*self.block_number.write() = Box::new(move |hash| client
|
||||||
|
.upgrade()
|
||||||
|
.ok_or("No client!".into())
|
||||||
|
.and_then(|c| c.block_number(BlockId::Hash(*hash)).ok_or("Unknown block".into())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use util::*;
|
||||||
|
use types::ids::BlockId;
|
||||||
|
use spec::Spec;
|
||||||
|
use account_provider::AccountProvider;
|
||||||
|
use client::{BlockChainClient, EngineClient};
|
||||||
|
use ethkey::Secret;
|
||||||
|
use miner::MinerService;
|
||||||
|
use tests::helpers::{generate_dummy_client_with_spec_and_accounts, generate_dummy_client_with_spec_and_data};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn uses_current_set() {
|
||||||
|
::env_logger::init().unwrap();
|
||||||
|
let tap = Arc::new(AccountProvider::transient_provider());
|
||||||
|
let s0 = Secret::from_slice(&"0".sha3()).unwrap();
|
||||||
|
let v0 = tap.insert_account(s0.clone(), "").unwrap();
|
||||||
|
let v1 = tap.insert_account(Secret::from_slice(&"1".sha3()).unwrap(), "").unwrap();
|
||||||
|
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_multi, Some(tap));
|
||||||
|
client.engine().register_client(Arc::downgrade(&client));
|
||||||
|
|
||||||
|
// Make sure txs go through.
|
||||||
|
client.miner().set_gas_floor_target(1_000_000.into());
|
||||||
|
|
||||||
|
// Wrong signer for the first block.
|
||||||
|
client.miner().set_engine_signer(v1, "".into()).unwrap();
|
||||||
|
client.transact_contract(Default::default(), Default::default()).unwrap();
|
||||||
|
client.update_sealing();
|
||||||
|
assert_eq!(client.chain_info().best_block_number, 0);
|
||||||
|
// Right signer for the first block.
|
||||||
|
client.miner().set_engine_signer(v0, "".into()).unwrap();
|
||||||
|
client.update_sealing();
|
||||||
|
assert_eq!(client.chain_info().best_block_number, 1);
|
||||||
|
// This time v0 is wrong.
|
||||||
|
client.transact_contract(Default::default(), Default::default()).unwrap();
|
||||||
|
client.update_sealing();
|
||||||
|
assert_eq!(client.chain_info().best_block_number, 1);
|
||||||
|
client.miner().set_engine_signer(v1, "".into()).unwrap();
|
||||||
|
client.update_sealing();
|
||||||
|
assert_eq!(client.chain_info().best_block_number, 2);
|
||||||
|
// v1 is still good.
|
||||||
|
client.transact_contract(Default::default(), Default::default()).unwrap();
|
||||||
|
client.update_sealing();
|
||||||
|
assert_eq!(client.chain_info().best_block_number, 3);
|
||||||
|
|
||||||
|
// Check syncing.
|
||||||
|
let sync_client = generate_dummy_client_with_spec_and_data(Spec::new_validator_multi, 0, 0, &[]);
|
||||||
|
sync_client.engine().register_client(Arc::downgrade(&sync_client));
|
||||||
|
for i in 1..4 {
|
||||||
|
sync_client.import_block(client.block(BlockId::Number(i)).unwrap().into_inner()).unwrap();
|
||||||
|
}
|
||||||
|
sync_client.flush_queue();
|
||||||
|
assert_eq!(sync_client.chain_info().best_block_number, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,17 +17,23 @@
|
|||||||
/// Validator set maintained in a contract, updated using `getValidators` method.
|
/// Validator set maintained in a contract, updated using `getValidators` method.
|
||||||
|
|
||||||
use std::sync::Weak;
|
use std::sync::Weak;
|
||||||
|
use ethabi;
|
||||||
use util::*;
|
use util::*;
|
||||||
|
use util::cache::MemoryLruCache;
|
||||||
|
use types::ids::BlockId;
|
||||||
use client::{Client, BlockChainClient};
|
use client::{Client, BlockChainClient};
|
||||||
use client::chain_notify::ChainNotify;
|
|
||||||
use super::ValidatorSet;
|
use super::ValidatorSet;
|
||||||
use super::simple_list::SimpleList;
|
use super::simple_list::SimpleList;
|
||||||
|
|
||||||
|
const MEMOIZE_CAPACITY: usize = 500;
|
||||||
|
const CONTRACT_INTERFACE: &'static [u8] = b"[{\"constant\":true,\"inputs\":[],\"name\":\"getValidators\",\"outputs\":[{\"name\":\"\",\"type\":\"address[]\"}],\"payable\":false,\"type\":\"function\"}]";
|
||||||
|
const GET_VALIDATORS: &'static str = "getValidators";
|
||||||
|
|
||||||
/// The validator contract should have the following interface:
|
/// The validator contract should have the following interface:
|
||||||
/// [{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"","type":"address[]"}],"payable":false,"type":"function"}]
|
/// [{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"","type":"address[]"}],"payable":false,"type":"function"}]
|
||||||
pub struct ValidatorSafeContract {
|
pub struct ValidatorSafeContract {
|
||||||
pub address: Address,
|
pub address: Address,
|
||||||
validators: RwLock<SimpleList>,
|
validators: RwLock<MemoryLruCache<H256, SimpleList>>,
|
||||||
provider: RwLock<Option<provider::Contract>>,
|
provider: RwLock<Option<provider::Contract>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,102 +41,127 @@ impl ValidatorSafeContract {
|
|||||||
pub fn new(contract_address: Address) -> Self {
|
pub fn new(contract_address: Address) -> Self {
|
||||||
ValidatorSafeContract {
|
ValidatorSafeContract {
|
||||||
address: contract_address,
|
address: contract_address,
|
||||||
validators: Default::default(),
|
validators: RwLock::new(MemoryLruCache::new(MEMOIZE_CAPACITY)),
|
||||||
provider: RwLock::new(None),
|
provider: RwLock::new(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Queries the state and updates the set of validators.
|
/// Queries the state and gets the set of validators.
|
||||||
pub fn update(&self) {
|
fn get_list(&self, block_hash: H256) -> Option<SimpleList> {
|
||||||
if let Some(ref provider) = *self.provider.read() {
|
if let Some(ref provider) = *self.provider.read() {
|
||||||
match provider.get_validators() {
|
match provider.get_validators(BlockId::Hash(block_hash)) {
|
||||||
Ok(new) => {
|
Ok(new) => {
|
||||||
debug!(target: "engine", "Set of validators obtained: {:?}", new);
|
debug!(target: "engine", "Set of validators obtained: {:?}", new);
|
||||||
*self.validators.write() = SimpleList::new(new);
|
Some(SimpleList::new(new))
|
||||||
|
},
|
||||||
|
Err(s) => {
|
||||||
|
debug!(target: "engine", "Set of validators could not be updated: {}", s);
|
||||||
|
None
|
||||||
},
|
},
|
||||||
Err(s) => warn!(target: "engine", "Set of validators could not be updated: {}", s),
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
warn!(target: "engine", "Set of validators could not be updated: no provider contract.")
|
warn!(target: "engine", "Set of validators could not be updated: no provider contract.");
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks validators on every block.
|
impl ValidatorSet for ValidatorSafeContract {
|
||||||
impl ChainNotify for ValidatorSafeContract {
|
fn contains(&self, block_hash: &H256, address: &Address) -> bool {
|
||||||
fn new_blocks(
|
let mut guard = self.validators.write();
|
||||||
&self,
|
let maybe_existing = guard
|
||||||
_: Vec<H256>,
|
.get_mut(block_hash)
|
||||||
_: Vec<H256>,
|
.map(|list| list.contains(block_hash, address));
|
||||||
enacted: Vec<H256>,
|
maybe_existing
|
||||||
_: Vec<H256>,
|
.unwrap_or_else(|| self
|
||||||
_: Vec<H256>,
|
.get_list(block_hash.clone())
|
||||||
_: Vec<Bytes>,
|
.map_or(false, |list| {
|
||||||
_duration: u64) {
|
let contains = list.contains(block_hash, address);
|
||||||
if !enacted.is_empty() {
|
guard.insert(block_hash.clone(), list);
|
||||||
self.update();
|
contains
|
||||||
}
|
}))
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ValidatorSet for Arc<ValidatorSafeContract> {
|
|
||||||
fn contains(&self, address: &Address) -> bool {
|
|
||||||
self.validators.read().contains(address)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self, nonce: usize) -> Address {
|
fn get(&self, block_hash: &H256, nonce: usize) -> Address {
|
||||||
self.validators.read().get(nonce)
|
let mut guard = self.validators.write();
|
||||||
|
let maybe_existing = guard
|
||||||
|
.get_mut(block_hash)
|
||||||
|
.map(|list| list.get(block_hash, nonce));
|
||||||
|
maybe_existing
|
||||||
|
.unwrap_or_else(|| self
|
||||||
|
.get_list(block_hash.clone())
|
||||||
|
.map_or_else(Default::default, |list| {
|
||||||
|
let address = list.get(block_hash, nonce);
|
||||||
|
guard.insert(block_hash.clone(), list);
|
||||||
|
address
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count(&self) -> usize {
|
fn count(&self, block_hash: &H256) -> usize {
|
||||||
self.validators.read().count()
|
let mut guard = self.validators.write();
|
||||||
|
let maybe_existing = guard
|
||||||
|
.get_mut(block_hash)
|
||||||
|
.map(|list| list.count(block_hash));
|
||||||
|
maybe_existing
|
||||||
|
.unwrap_or_else(|| self
|
||||||
|
.get_list(block_hash.clone())
|
||||||
|
.map_or_else(usize::max_value, |list| {
|
||||||
|
let address = list.count(block_hash);
|
||||||
|
guard.insert(block_hash.clone(), list);
|
||||||
|
address
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_contract(&self, client: Weak<Client>) {
|
fn register_contract(&self, client: Weak<Client>) {
|
||||||
if let Some(c) = client.upgrade() {
|
trace!(target: "engine", "Setting up contract caller.");
|
||||||
c.add_notify(self.clone());
|
let contract = ethabi::Contract::new(ethabi::Interface::load(CONTRACT_INTERFACE).expect("JSON interface is valid; qed"));
|
||||||
}
|
let call = contract.function(GET_VALIDATORS.into()).expect("Method name is valid; qed");
|
||||||
{
|
let data = call.encode_call(vec![]).expect("get_validators does not take any arguments; qed");
|
||||||
*self.provider.write() = Some(provider::Contract::new(self.address, move |a, d| client.upgrade().ok_or("No client!".into()).and_then(|c| c.call_contract(a, d))));
|
let contract_address = self.address.clone();
|
||||||
}
|
let do_call = move |id| client
|
||||||
self.update();
|
.upgrade()
|
||||||
|
.ok_or("No client!".into())
|
||||||
|
.and_then(|c| c.call_contract(id, contract_address.clone(), data.clone()))
|
||||||
|
.map(|raw_output| call.decode_output(raw_output).expect("ethabi is correct; qed"));
|
||||||
|
*self.provider.write() = Some(provider::Contract::new(do_call));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod provider {
|
mod provider {
|
||||||
// Autogenerated from JSON contract definition using Rust contract convertor.
|
|
||||||
#![allow(unused_imports)]
|
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
use std::result::Result;
|
use std::result::Result;
|
||||||
use std::fmt;
|
|
||||||
use {util, ethabi};
|
use {util, ethabi};
|
||||||
use util::{FixedHash, Uint};
|
use types::ids::BlockId;
|
||||||
|
|
||||||
pub struct Contract {
|
pub struct Contract {
|
||||||
contract: ethabi::Contract,
|
do_call: Box<Fn(BlockId) -> Result<Vec<ethabi::Token>, String> + Send + Sync + 'static>,
|
||||||
address: util::Address,
|
|
||||||
do_call: Box<Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send + Sync + 'static>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Contract {
|
impl Contract {
|
||||||
pub fn new<F>(address: util::Address, do_call: F) -> Self where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send + Sync + 'static {
|
pub fn new<F>(do_call: F) -> Self where F: Fn(BlockId) -> Result<Vec<ethabi::Token>, String> + Send + Sync + 'static {
|
||||||
Contract {
|
Contract {
|
||||||
contract: ethabi::Contract::new(ethabi::Interface::load(b"[{\"constant\":true,\"inputs\":[],\"name\":\"getValidators\",\"outputs\":[{\"name\":\"\",\"type\":\"address[]\"}],\"payable\":false,\"type\":\"function\"}]").expect("JSON is autogenerated; qed")),
|
|
||||||
address: address,
|
|
||||||
do_call: Box::new(do_call),
|
do_call: Box::new(do_call),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn as_string<T: fmt::Debug>(e: T) -> String { format!("{:?}", e) }
|
|
||||||
|
/// Gets validators from contract with interface: `{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"","type":"address[]"}],"payable":false,"type":"function"}`
|
||||||
/// Auto-generated from: `{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"","type":"address[]"}],"payable":false,"type":"function"}`
|
pub fn get_validators(&self, id: BlockId) -> Result<Vec<util::Address>, String> {
|
||||||
#[allow(dead_code)]
|
Ok((self.do_call)(id)?
|
||||||
pub fn get_validators(&self) -> Result<Vec<util::Address>, String> {
|
.into_iter()
|
||||||
let call = self.contract.function("getValidators".into()).map_err(Self::as_string)?;
|
.rev()
|
||||||
let data = call.encode_call(
|
.collect::<Vec<_>>()
|
||||||
vec![]
|
.pop()
|
||||||
).map_err(Self::as_string)?;
|
.expect("get_validators returns one argument; qed")
|
||||||
let output = call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
|
.to_array()
|
||||||
let mut result = output.into_iter().rev().collect::<Vec<_>>();
|
.and_then(|v| v
|
||||||
Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_array().and_then(|v| v.into_iter().map(|a| a.to_address()).collect::<Option<Vec<[u8; 20]>>>()).ok_or("Invalid type returned")?; r.into_iter().map(|a| util::Address::from(a)).collect::<Vec<_>>() }))
|
.into_iter()
|
||||||
|
.map(|a| a.to_address())
|
||||||
|
.collect::<Option<Vec<[u8; 20]>>>())
|
||||||
|
.expect("get_validators returns a list of addresses; qed")
|
||||||
|
.into_iter()
|
||||||
|
.map(util::Address::from)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,13 +169,14 @@ mod provider {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use util::*;
|
use util::*;
|
||||||
|
use types::ids::BlockId;
|
||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
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 ethkey::Secret;
|
||||||
use miner::MinerService;
|
use miner::MinerService;
|
||||||
use tests::helpers::generate_dummy_client_with_spec_and_accounts;
|
use tests::helpers::{generate_dummy_client_with_spec_and_accounts, generate_dummy_client_with_spec_and_data};
|
||||||
use super::super::ValidatorSet;
|
use super::super::ValidatorSet;
|
||||||
use super::ValidatorSafeContract;
|
use super::ValidatorSafeContract;
|
||||||
|
|
||||||
@@ -153,12 +185,13 @@ mod tests {
|
|||||||
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, None);
|
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, None);
|
||||||
let vc = Arc::new(ValidatorSafeContract::new(Address::from_str("0000000000000000000000000000000000000005").unwrap()));
|
let vc = Arc::new(ValidatorSafeContract::new(Address::from_str("0000000000000000000000000000000000000005").unwrap()));
|
||||||
vc.register_contract(Arc::downgrade(&client));
|
vc.register_contract(Arc::downgrade(&client));
|
||||||
assert!(vc.contains(&Address::from_str("7d577a597b2742b498cb5cf0c26cdcd726d39e6e").unwrap()));
|
let last_hash = client.best_block_header().hash();
|
||||||
assert!(vc.contains(&Address::from_str("82a978b3f5962a5b0957d9ee9eef472ee55b42f1").unwrap()));
|
assert!(vc.contains(&last_hash, &Address::from_str("7d577a597b2742b498cb5cf0c26cdcd726d39e6e").unwrap()));
|
||||||
|
assert!(vc.contains(&last_hash, &Address::from_str("82a978b3f5962a5b0957d9ee9eef472ee55b42f1").unwrap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn updates_validators() {
|
fn knows_validators() {
|
||||||
let tap = Arc::new(AccountProvider::transient_provider());
|
let tap = Arc::new(AccountProvider::transient_provider());
|
||||||
let s0 = Secret::from_slice(&"1".sha3()).unwrap();
|
let s0 = Secret::from_slice(&"1".sha3()).unwrap();
|
||||||
let v0 = tap.insert_account(s0.clone(), "").unwrap();
|
let v0 = tap.insert_account(s0.clone(), "").unwrap();
|
||||||
@@ -212,5 +245,14 @@ mod tests {
|
|||||||
client.update_sealing();
|
client.update_sealing();
|
||||||
// Able to seal again.
|
// Able to seal again.
|
||||||
assert_eq!(client.chain_info().best_block_number, 3);
|
assert_eq!(client.chain_info().best_block_number, 3);
|
||||||
|
|
||||||
|
// Check syncing.
|
||||||
|
let sync_client = generate_dummy_client_with_spec_and_data(Spec::new_validator_safe_contract, 0, 0, &[]);
|
||||||
|
sync_client.engine().register_client(Arc::downgrade(&sync_client));
|
||||||
|
for i in 1..4 {
|
||||||
|
sync_client.import_block(client.block(BlockId::Number(i)).unwrap().into_inner()).unwrap();
|
||||||
|
}
|
||||||
|
sync_client.flush_queue();
|
||||||
|
assert_eq!(sync_client.chain_info().best_block_number, 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
/// Preconfigured validator list.
|
/// Preconfigured validator list.
|
||||||
|
|
||||||
use util::Address;
|
use util::{H256, Address, HeapSizeOf};
|
||||||
use super::ValidatorSet;
|
use super::ValidatorSet;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Default)]
|
#[derive(Debug, PartialEq, Eq, Default)]
|
||||||
@@ -34,16 +34,22 @@ impl SimpleList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl HeapSizeOf for SimpleList {
|
||||||
|
fn heap_size_of_children(&self) -> usize {
|
||||||
|
self.validators.heap_size_of_children() + self.validator_n.heap_size_of_children()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ValidatorSet for SimpleList {
|
impl ValidatorSet for SimpleList {
|
||||||
fn contains(&self, address: &Address) -> bool {
|
fn contains(&self, _bh: &H256, address: &Address) -> bool {
|
||||||
self.validators.contains(address)
|
self.validators.contains(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self, nonce: usize) -> Address {
|
fn get(&self, _bh: &H256, nonce: usize) -> Address {
|
||||||
self.validators.get(nonce % self.validator_n).expect("There are validator_n authorities; taking number modulo validator_n gives number in validator_n range; qed").clone()
|
self.validators.get(nonce % self.validator_n).expect("There are validator_n authorities; taking number modulo validator_n gives number in validator_n range; qed").clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count(&self) -> usize {
|
fn count(&self, _bh: &H256) -> usize {
|
||||||
self.validator_n
|
self.validator_n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,9 +66,9 @@ mod tests {
|
|||||||
let a1 = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap();
|
let a1 = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap();
|
||||||
let a2 = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
let a2 = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||||
let list = SimpleList::new(vec![a1.clone(), a2.clone()]);
|
let list = SimpleList::new(vec![a1.clone(), a2.clone()]);
|
||||||
assert!(list.contains(&a1));
|
assert!(list.contains(&Default::default(), &a1));
|
||||||
assert_eq!(list.get(0), a1);
|
assert_eq!(list.get(&Default::default(), 0), a1);
|
||||||
assert_eq!(list.get(1), a2);
|
assert_eq!(list.get(&Default::default(), 1), a2);
|
||||||
assert_eq!(list.get(2), a1);
|
assert_eq!(list.get(&Default::default(), 2), a1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,6 +129,8 @@ pub enum BlockError {
|
|||||||
UncleIsBrother(OutOfBounds<BlockNumber>),
|
UncleIsBrother(OutOfBounds<BlockNumber>),
|
||||||
/// An uncle is already in the chain.
|
/// An uncle is already in the chain.
|
||||||
UncleInChain(H256),
|
UncleInChain(H256),
|
||||||
|
/// An uncle is included twice.
|
||||||
|
DuplicateUncle(H256),
|
||||||
/// An uncle has a parent not in the chain.
|
/// An uncle has a parent not in the chain.
|
||||||
UncleParentNotInChain(H256),
|
UncleParentNotInChain(H256),
|
||||||
/// State root header field is invalid.
|
/// State root header field is invalid.
|
||||||
@@ -184,6 +186,7 @@ impl fmt::Display for BlockError {
|
|||||||
UncleTooOld(ref oob) => format!("Uncle block is too old. {}", oob),
|
UncleTooOld(ref oob) => format!("Uncle block is too old. {}", oob),
|
||||||
UncleIsBrother(ref oob) => format!("Uncle from same generation as block. {}", oob),
|
UncleIsBrother(ref oob) => format!("Uncle from same generation as block. {}", oob),
|
||||||
UncleInChain(ref hash) => format!("Uncle {} already in chain", hash),
|
UncleInChain(ref hash) => format!("Uncle {} already in chain", hash),
|
||||||
|
DuplicateUncle(ref hash) => format!("Uncle {} already in the header", hash),
|
||||||
UncleParentNotInChain(ref hash) => format!("Uncle {} has a parent not in the chain", hash),
|
UncleParentNotInChain(ref hash) => format!("Uncle {} has a parent not in the chain", hash),
|
||||||
InvalidStateRoot(ref mis) => format!("Invalid state root in header: {}", mis),
|
InvalidStateRoot(ref mis) => format!("Invalid state root in header: {}", mis),
|
||||||
InvalidGasUsed(ref mis) => format!("Invalid gas used in header: {}", mis),
|
InvalidGasUsed(ref mis) => format!("Invalid gas used in header: {}", mis),
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ pub struct EthashParams {
|
|||||||
pub ecip1010_pause_transition: u64,
|
pub ecip1010_pause_transition: u64,
|
||||||
/// Number of first block where ECIP-1010 ends.
|
/// Number of first block where ECIP-1010 ends.
|
||||||
pub ecip1010_continue_transition: u64,
|
pub ecip1010_continue_transition: u64,
|
||||||
|
/// Total block number for one ECIP-1017 era.
|
||||||
|
pub ecip1017_era_rounds: u64,
|
||||||
/// Maximum amount of code that can be deploying into a contract.
|
/// Maximum amount of code that can be deploying into a contract.
|
||||||
pub max_code_size: u64,
|
pub max_code_size: u64,
|
||||||
/// Number of first block where the max gas limit becomes effective.
|
/// Number of first block where the max gas limit becomes effective.
|
||||||
@@ -113,6 +115,7 @@ impl From<ethjson::spec::EthashParams> for EthashParams {
|
|||||||
eip161d_transition: p.eip161d_transition.map_or(u64::max_value(), Into::into),
|
eip161d_transition: p.eip161d_transition.map_or(u64::max_value(), Into::into),
|
||||||
ecip1010_pause_transition: p.ecip1010_pause_transition.map_or(u64::max_value(), Into::into),
|
ecip1010_pause_transition: p.ecip1010_pause_transition.map_or(u64::max_value(), Into::into),
|
||||||
ecip1010_continue_transition: p.ecip1010_continue_transition.map_or(u64::max_value(), Into::into),
|
ecip1010_continue_transition: p.ecip1010_continue_transition.map_or(u64::max_value(), Into::into),
|
||||||
|
ecip1017_era_rounds: p.ecip1017_era_rounds.map_or(u64::max_value(), Into::into),
|
||||||
max_code_size: p.max_code_size.map_or(u64::max_value(), Into::into),
|
max_code_size: p.max_code_size.map_or(u64::max_value(), Into::into),
|
||||||
max_gas_limit_transition: p.max_gas_limit_transition.map_or(u64::max_value(), Into::into),
|
max_gas_limit_transition: p.max_gas_limit_transition.map_or(u64::max_value(), Into::into),
|
||||||
max_gas_limit: p.max_gas_limit.map_or(U256::max_value(), Into::into),
|
max_gas_limit: p.max_gas_limit.map_or(U256::max_value(), Into::into),
|
||||||
@@ -249,6 +252,8 @@ impl Engine for Ethash {
|
|||||||
fn on_close_block(&self, block: &mut ExecutedBlock) {
|
fn on_close_block(&self, block: &mut ExecutedBlock) {
|
||||||
let reward = self.ethash_params.block_reward;
|
let reward = self.ethash_params.block_reward;
|
||||||
let fields = block.fields_mut();
|
let fields = block.fields_mut();
|
||||||
|
let eras_rounds = self.ethash_params.ecip1017_era_rounds;
|
||||||
|
let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, reward, fields.header.number());
|
||||||
|
|
||||||
// Bestow block reward
|
// Bestow block reward
|
||||||
let res = fields.state.add_balance(
|
let res = fields.state.add_balance(
|
||||||
@@ -264,12 +269,19 @@ impl Engine for Ethash {
|
|||||||
// Bestow uncle rewards
|
// Bestow uncle rewards
|
||||||
let current_number = fields.header.number();
|
let current_number = fields.header.number();
|
||||||
for u in fields.uncles.iter() {
|
for u in fields.uncles.iter() {
|
||||||
let res = fields.state.add_balance(
|
let res = if eras == 0 {
|
||||||
u.author(),
|
fields.state.add_balance(
|
||||||
&(reward * U256::from(8 + u.number() - current_number) / U256::from(8)),
|
u.author(),
|
||||||
CleanupMode::NoEmpty
|
&(reward * U256::from(8 + u.number() - current_number) / U256::from(8)),
|
||||||
);
|
CleanupMode::NoEmpty
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
fields.state.add_balance(
|
||||||
|
u.author(),
|
||||||
|
&(reward / U256::from(32)),
|
||||||
|
CleanupMode::NoEmpty
|
||||||
|
)
|
||||||
|
};
|
||||||
if let Err(e) = res {
|
if let Err(e) = res {
|
||||||
warn!("Failed to give uncle reward: {}", e);
|
warn!("Failed to give uncle reward: {}", e);
|
||||||
}
|
}
|
||||||
@@ -398,6 +410,18 @@ fn round_block_gas_limit(gas_limit: U256, lower_limit: U256, upper_limit: U256)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ecip1017_eras_block_reward(era_rounds: u64, mut reward: U256, block_number:u64) -> (u64, U256){
|
||||||
|
let eras = if block_number != 0 && block_number % era_rounds == 0 {
|
||||||
|
block_number / era_rounds - 1
|
||||||
|
} else {
|
||||||
|
block_number / era_rounds
|
||||||
|
};
|
||||||
|
for _ in 0..eras {
|
||||||
|
reward = reward / U256::from(5) * U256::from(4);
|
||||||
|
}
|
||||||
|
(eras, reward)
|
||||||
|
}
|
||||||
|
|
||||||
#[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 {
|
||||||
@@ -500,7 +524,7 @@ mod tests {
|
|||||||
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, PARITY_GAS_LIMIT_DETERMINANT};
|
use super::{Ethash, EthashParams, PARITY_GAS_LIMIT_DETERMINANT, ecip1017_eras_block_reward};
|
||||||
use rlp;
|
use rlp;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -756,6 +780,42 @@ mod tests {
|
|||||||
assert_eq!(U256::from_str("1fc50f118efe").unwrap(), difficulty);
|
assert_eq!(U256::from_str("1fc50f118efe").unwrap(), difficulty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn has_valid_ecip1017_eras_block_reward() {
|
||||||
|
let ethparams = EthashParams {
|
||||||
|
// see ethcore/res/ethereum/classic.json
|
||||||
|
ecip1017_era_rounds: 5000000,
|
||||||
|
block_reward: U256::from_str("4563918244F40000").unwrap(),
|
||||||
|
..get_default_ethash_params()
|
||||||
|
};
|
||||||
|
let eras_rounds = ethparams.ecip1017_era_rounds;
|
||||||
|
let reward = ethparams.block_reward;
|
||||||
|
let block_number = 0;
|
||||||
|
let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, reward, block_number);
|
||||||
|
assert_eq!(0, eras);
|
||||||
|
assert_eq!(U256::from_str("4563918244F40000").unwrap(), reward);
|
||||||
|
let reward = ethparams.block_reward;
|
||||||
|
let block_number = 5000000;
|
||||||
|
let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, reward, block_number);
|
||||||
|
assert_eq!(0, eras);
|
||||||
|
assert_eq!(U256::from_str("4563918244F40000").unwrap(), reward);
|
||||||
|
let reward = ethparams.block_reward;
|
||||||
|
let block_number = 10000000;
|
||||||
|
let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, reward, block_number);
|
||||||
|
assert_eq!(1, eras);
|
||||||
|
assert_eq!(U256::from_str("3782DACE9D900000").unwrap(), reward);
|
||||||
|
let reward = ethparams.block_reward;
|
||||||
|
let block_number = 20000000;
|
||||||
|
let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, reward, block_number);
|
||||||
|
assert_eq!(3, eras);
|
||||||
|
assert_eq!(U256::from_str("2386F26FC1000000").unwrap(), reward);
|
||||||
|
let reward = ethparams.block_reward;
|
||||||
|
let block_number = 80000000;
|
||||||
|
let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, reward, block_number);
|
||||||
|
assert_eq!(15, eras);
|
||||||
|
assert_eq!(U256::from_str("271000000000000").unwrap(), reward);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn difficulty_classic_bomb_delay() {
|
fn difficulty_classic_bomb_delay() {
|
||||||
let spec = new_homestead_test();
|
let spec = new_homestead_test();
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ extern crate ethcore_stratum;
|
|||||||
extern crate ethabi;
|
extern crate ethabi;
|
||||||
extern crate hardware_wallet;
|
extern crate hardware_wallet;
|
||||||
extern crate stats;
|
extern crate stats;
|
||||||
|
extern crate itertools;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|||||||
@@ -88,6 +88,8 @@ pub struct MinerOptions {
|
|||||||
pub reseal_on_external_tx: bool,
|
pub reseal_on_external_tx: bool,
|
||||||
/// Reseal on receipt of new local transactions.
|
/// Reseal on receipt of new local transactions.
|
||||||
pub reseal_on_own_tx: bool,
|
pub reseal_on_own_tx: bool,
|
||||||
|
/// Reseal when new uncle block has been imported.
|
||||||
|
pub reseal_on_uncle: bool,
|
||||||
/// Minimum period between transaction-inspired reseals.
|
/// Minimum period between transaction-inspired reseals.
|
||||||
pub reseal_min_period: Duration,
|
pub reseal_min_period: Duration,
|
||||||
/// Maximum amount of gas to bother considering for block insertion.
|
/// Maximum amount of gas to bother considering for block insertion.
|
||||||
@@ -117,6 +119,7 @@ impl Default for MinerOptions {
|
|||||||
force_sealing: false,
|
force_sealing: false,
|
||||||
reseal_on_external_tx: false,
|
reseal_on_external_tx: false,
|
||||||
reseal_on_own_tx: true,
|
reseal_on_own_tx: true,
|
||||||
|
reseal_on_uncle: false,
|
||||||
tx_gas_limit: !U256::zero(),
|
tx_gas_limit: !U256::zero(),
|
||||||
tx_queue_size: 1024,
|
tx_queue_size: 1024,
|
||||||
tx_queue_gas_limit: GasLimit::Auto,
|
tx_queue_gas_limit: GasLimit::Auto,
|
||||||
@@ -230,7 +233,8 @@ pub struct Miner {
|
|||||||
impl Miner {
|
impl Miner {
|
||||||
/// Push notifier that will handle new jobs
|
/// Push notifier that will handle new jobs
|
||||||
pub fn push_notifier(&self, notifier: Box<NotifyWork>) {
|
pub fn push_notifier(&self, notifier: Box<NotifyWork>) {
|
||||||
self.notifiers.write().push(notifier)
|
self.notifiers.write().push(notifier);
|
||||||
|
self.sealing_work.lock().enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates new instance of miner Arc.
|
/// Creates new instance of miner Arc.
|
||||||
@@ -298,7 +302,7 @@ impl Miner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn forced_sealing(&self) -> bool {
|
fn forced_sealing(&self) -> bool {
|
||||||
self.options.force_sealing || !self.options.new_work_notify.is_empty()
|
self.options.force_sealing || !self.notifiers.read().is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clear all pending block states
|
/// Clear all pending block states
|
||||||
@@ -338,7 +342,7 @@ impl Miner {
|
|||||||
Some(old_block) => {
|
Some(old_block) => {
|
||||||
trace!(target: "miner", "prepare_block: Already have previous work; updating and returning");
|
trace!(target: "miner", "prepare_block: Already have previous work; updating and returning");
|
||||||
// add transactions to old_block
|
// add transactions to old_block
|
||||||
old_block.reopen(&*self.engine)
|
chain.reopen_block(old_block)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// block not found - create it.
|
// block not found - create it.
|
||||||
@@ -357,7 +361,6 @@ impl Miner {
|
|||||||
let mut transactions_to_penalize = HashSet::new();
|
let mut transactions_to_penalize = HashSet::new();
|
||||||
let block_number = open_block.block().fields().header.number();
|
let block_number = open_block.block().fields().header.number();
|
||||||
|
|
||||||
// TODO Push new uncles too.
|
|
||||||
let mut tx_count: usize = 0;
|
let mut tx_count: usize = 0;
|
||||||
let tx_total = transactions.len();
|
let tx_total = transactions.len();
|
||||||
for tx in transactions {
|
for tx in transactions {
|
||||||
@@ -1007,6 +1010,16 @@ impl MinerService for Miner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn remove_pending_transaction(&self, chain: &MiningBlockChainClient, hash: &H256) -> Option<PendingTransaction> {
|
||||||
|
let mut queue = self.transaction_queue.lock();
|
||||||
|
let tx = queue.find(hash);
|
||||||
|
if tx.is_some() {
|
||||||
|
let fetch_nonce = |a: &Address| chain.latest_nonce(a);
|
||||||
|
queue.remove_invalid(hash, &fetch_nonce);
|
||||||
|
}
|
||||||
|
tx
|
||||||
|
}
|
||||||
|
|
||||||
fn pending_receipt(&self, best_block: BlockNumber, hash: &H256) -> Option<RichReceipt> {
|
fn pending_receipt(&self, best_block: BlockNumber, hash: &H256) -> Option<RichReceipt> {
|
||||||
self.from_pending_block(
|
self.from_pending_block(
|
||||||
best_block,
|
best_block,
|
||||||
@@ -1131,11 +1144,10 @@ impl MinerService for Miner {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chain_new_blocks(&self, chain: &MiningBlockChainClient, _imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256]) {
|
fn chain_new_blocks(&self, chain: &MiningBlockChainClient, imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256]) {
|
||||||
trace!(target: "miner", "chain_new_blocks");
|
trace!(target: "miner", "chain_new_blocks");
|
||||||
|
|
||||||
// 1. We ignore blocks that were `imported` (because it means that they are not in canon-chain, and transactions
|
// 1. We ignore blocks that were `imported` unless resealing on new uncles is enabled.
|
||||||
// should be still available in the queue.
|
|
||||||
// 2. We ignore blocks that are `invalid` because it doesn't have any meaning in terms of the transactions that
|
// 2. We ignore blocks that are `invalid` because it doesn't have any meaning in terms of the transactions that
|
||||||
// are in those blocks
|
// are in those blocks
|
||||||
|
|
||||||
@@ -1170,7 +1182,7 @@ impl MinerService for Miner {
|
|||||||
transaction_queue.remove_old(&fetch_account, time);
|
transaction_queue.remove_old(&fetch_account, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
if enacted.len() > 0 {
|
if enacted.len() > 0 || (imported.len() > 0 && self.options.reseal_on_uncle) {
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// | 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. |
|
||||||
@@ -1289,6 +1301,7 @@ mod tests {
|
|||||||
force_sealing: false,
|
force_sealing: false,
|
||||||
reseal_on_external_tx: false,
|
reseal_on_external_tx: false,
|
||||||
reseal_on_own_tx: true,
|
reseal_on_own_tx: true,
|
||||||
|
reseal_on_uncle: false,
|
||||||
reseal_min_period: Duration::from_secs(5),
|
reseal_min_period: Duration::from_secs(5),
|
||||||
tx_gas_limit: !U256::zero(),
|
tx_gas_limit: !U256::zero(),
|
||||||
tx_queue_size: 1024,
|
tx_queue_size: 1024,
|
||||||
|
|||||||
@@ -150,6 +150,10 @@ pub trait MinerService : Send + Sync {
|
|||||||
/// Query pending transactions for hash.
|
/// Query pending transactions for hash.
|
||||||
fn transaction(&self, best_block: BlockNumber, hash: &H256) -> Option<PendingTransaction>;
|
fn transaction(&self, best_block: BlockNumber, hash: &H256) -> Option<PendingTransaction>;
|
||||||
|
|
||||||
|
/// Removes transaction from the queue.
|
||||||
|
/// NOTE: The transaction is not removed from pending block if mining.
|
||||||
|
fn remove_pending_transaction(&self, chain: &MiningBlockChainClient, hash: &H256) -> Option<PendingTransaction>;
|
||||||
|
|
||||||
/// Get a list of all pending transactions in the queue.
|
/// Get a list of all pending transactions in the queue.
|
||||||
fn pending_transactions(&self) -> Vec<PendingTransaction>;
|
fn pending_transactions(&self) -> Vec<PendingTransaction>;
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +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/>.
|
||||||
|
|
||||||
|
use types::ids::BlockId;
|
||||||
use client::MiningBlockChainClient;
|
use client::MiningBlockChainClient;
|
||||||
use transaction::SignedTransaction;
|
use transaction::SignedTransaction;
|
||||||
use util::{U256, Uint, Mutex};
|
use util::{U256, Uint, Mutex};
|
||||||
@@ -45,7 +46,7 @@ impl ServiceTransactionChecker {
|
|||||||
debug_assert_eq!(tx.gas_price, U256::zero());
|
debug_assert_eq!(tx.gas_price, U256::zero());
|
||||||
|
|
||||||
if let Some(ref contract) = *self.contract.lock() {
|
if let Some(ref contract) = *self.contract.lock() {
|
||||||
let do_call = |a, d| client.call_contract(a, d);
|
let do_call = |a, d| client.call_contract(BlockId::Latest, a, d);
|
||||||
contract.certified(&do_call, &tx.sender())
|
contract.certified(&do_call, &tx.sender())
|
||||||
} else {
|
} else {
|
||||||
Err("contract is not configured".to_owned())
|
Err("contract is not configured".to_owned())
|
||||||
|
|||||||
@@ -211,6 +211,8 @@ impl From<AddrParseError> for Error {
|
|||||||
|
|
||||||
impl super::work_notify::NotifyWork for Stratum {
|
impl super::work_notify::NotifyWork for Stratum {
|
||||||
fn notify(&self, pow_hash: H256, difficulty: U256, number: u64) {
|
fn notify(&self, pow_hash: H256, difficulty: U256, number: u64) {
|
||||||
|
trace!(target: "stratum", "Notify work");
|
||||||
|
|
||||||
self.service.push_work_all(
|
self.service.push_work_all(
|
||||||
self.dispatcher.payload(pow_hash, difficulty, number)
|
self.dispatcher.payload(pow_hash, difficulty, number)
|
||||||
).unwrap_or_else(
|
).unwrap_or_else(
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ use snapshot::Error;
|
|||||||
use util::{U256, FixedHash, H256, Bytes, HashDB, SHA3_EMPTY, SHA3_NULL_RLP};
|
use util::{U256, FixedHash, H256, Bytes, HashDB, SHA3_EMPTY, SHA3_NULL_RLP};
|
||||||
use util::trie::{TrieDB, Trie};
|
use util::trie::{TrieDB, Trie};
|
||||||
use rlp::{RlpStream, Stream, UntrustedRlp, View};
|
use rlp::{RlpStream, Stream, UntrustedRlp, View};
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
@@ -60,55 +61,53 @@ impl CodeState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// walk the account's storage trie, returning an RLP item containing the
|
// walk the account's storage trie, returning a vector of RLP items containing the
|
||||||
// account properties and the storage.
|
// account properties and the storage. Each item contains at most `max_storage_items`
|
||||||
pub fn to_fat_rlp(acc: &BasicAccount, acct_db: &AccountDB, used_code: &mut HashSet<H256>) -> Result<Bytes, Error> {
|
// storage records split according to snapshot format definition.
|
||||||
|
pub fn to_fat_rlps(acc: &BasicAccount, acct_db: &AccountDB, used_code: &mut HashSet<H256>, max_storage_items: usize) -> Result<Vec<Bytes>, Error> {
|
||||||
if acc == &ACC_EMPTY {
|
if acc == &ACC_EMPTY {
|
||||||
return Ok(::rlp::NULL_RLP.to_vec());
|
return Ok(vec![::rlp::NULL_RLP.to_vec()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let db = TrieDB::new(acct_db, &acc.storage_root)?;
|
let db = TrieDB::new(acct_db, &acc.storage_root)?;
|
||||||
|
|
||||||
let mut pairs = Vec::new();
|
let chunks = db.iter()?.chunks(max_storage_items);
|
||||||
|
let pair_chunks = chunks.into_iter().map(|chunk| chunk.collect());
|
||||||
|
pair_chunks.pad_using(1, |_| Vec::new(), ).map(|pairs| {
|
||||||
|
let mut stream = RlpStream::new_list(pairs.len());
|
||||||
|
|
||||||
for item in db.iter()? {
|
for r in pairs {
|
||||||
let (k, v) = item?;
|
let (k, v) = r?;
|
||||||
pairs.push((k, v));
|
stream.begin_list(2).append(&k).append(&&*v);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut stream = RlpStream::new_list(pairs.len());
|
let pairs_rlp = stream.out();
|
||||||
|
|
||||||
for (k, v) in pairs {
|
let mut account_stream = RlpStream::new_list(5);
|
||||||
stream.begin_list(2).append(&k).append(&&*v);
|
account_stream.append(&acc.nonce)
|
||||||
}
|
.append(&acc.balance);
|
||||||
|
|
||||||
let pairs_rlp = stream.out();
|
// [has_code, code_hash].
|
||||||
|
if acc.code_hash == SHA3_EMPTY {
|
||||||
let mut account_stream = RlpStream::new_list(5);
|
account_stream.append(&CodeState::Empty.raw()).append_empty_data();
|
||||||
account_stream.append(&acc.nonce)
|
} else if used_code.contains(&acc.code_hash) {
|
||||||
.append(&acc.balance);
|
account_stream.append(&CodeState::Hash.raw()).append(&acc.code_hash);
|
||||||
|
} else {
|
||||||
// [has_code, code_hash].
|
match acct_db.get(&acc.code_hash) {
|
||||||
if acc.code_hash == SHA3_EMPTY {
|
Some(c) => {
|
||||||
account_stream.append(&CodeState::Empty.raw()).append_empty_data();
|
used_code.insert(acc.code_hash.clone());
|
||||||
} else if used_code.contains(&acc.code_hash) {
|
account_stream.append(&CodeState::Inline.raw()).append(&&*c);
|
||||||
account_stream.append(&CodeState::Hash.raw()).append(&acc.code_hash);
|
}
|
||||||
} else {
|
None => {
|
||||||
match acct_db.get(&acc.code_hash) {
|
warn!("code lookup failed during snapshot");
|
||||||
Some(c) => {
|
account_stream.append(&false).append_empty_data();
|
||||||
used_code.insert(acc.code_hash.clone());
|
}
|
||||||
account_stream.append(&CodeState::Inline.raw()).append(&&*c);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
warn!("code lookup failed during snapshot");
|
|
||||||
account_stream.append(&false).append_empty_data();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
account_stream.append_raw(&pairs_rlp, 1);
|
account_stream.append_raw(&pairs_rlp, 1);
|
||||||
|
Ok(account_stream.out())
|
||||||
Ok(account_stream.out())
|
}).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
// decode a fat rlp, and rebuild the storage trie as we go.
|
// decode a fat rlp, and rebuild the storage trie as we go.
|
||||||
@@ -117,6 +116,7 @@ pub fn to_fat_rlp(acc: &BasicAccount, acct_db: &AccountDB, used_code: &mut HashS
|
|||||||
pub fn from_fat_rlp(
|
pub fn from_fat_rlp(
|
||||||
acct_db: &mut AccountDBMut,
|
acct_db: &mut AccountDBMut,
|
||||||
rlp: UntrustedRlp,
|
rlp: UntrustedRlp,
|
||||||
|
mut storage_root: H256,
|
||||||
) -> Result<(BasicAccount, Option<Bytes>), Error> {
|
) -> Result<(BasicAccount, Option<Bytes>), Error> {
|
||||||
use util::{TrieDBMut, TrieMut};
|
use util::{TrieDBMut, TrieMut};
|
||||||
|
|
||||||
@@ -148,10 +148,12 @@ pub fn from_fat_rlp(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut storage_root = H256::zero();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut storage_trie = TrieDBMut::new(acct_db, &mut storage_root);
|
let mut storage_trie = if storage_root.is_zero() {
|
||||||
|
TrieDBMut::new(acct_db, &mut storage_root)
|
||||||
|
} else {
|
||||||
|
TrieDBMut::from_existing(acct_db, &mut storage_root)?
|
||||||
|
};
|
||||||
let pairs = rlp.at(4)?;
|
let pairs = rlp.at(4)?;
|
||||||
for pair_rlp in pairs.iter() {
|
for pair_rlp in pairs.iter() {
|
||||||
let k: Bytes = pair_rlp.val_at(0)?;
|
let k: Bytes = pair_rlp.val_at(0)?;
|
||||||
@@ -184,7 +186,7 @@ mod tests {
|
|||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use super::{ACC_EMPTY, to_fat_rlp, from_fat_rlp};
|
use super::{ACC_EMPTY, to_fat_rlps, from_fat_rlp};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn encoding_basic() {
|
fn encoding_basic() {
|
||||||
@@ -201,9 +203,9 @@ mod tests {
|
|||||||
let thin_rlp = ::rlp::encode(&account);
|
let thin_rlp = ::rlp::encode(&account);
|
||||||
assert_eq!(::rlp::decode::<BasicAccount>(&thin_rlp), account);
|
assert_eq!(::rlp::decode::<BasicAccount>(&thin_rlp), account);
|
||||||
|
|
||||||
let fat_rlp = to_fat_rlp(&account, &AccountDB::new(db.as_hashdb(), &addr), &mut Default::default()).unwrap();
|
let fat_rlps = to_fat_rlps(&account, &AccountDB::new(db.as_hashdb(), &addr), &mut Default::default(), usize::max_value()).unwrap();
|
||||||
let fat_rlp = UntrustedRlp::new(&fat_rlp);
|
let fat_rlp = UntrustedRlp::new(&fat_rlps[0]);
|
||||||
assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp).unwrap().0, account);
|
assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp, H256::zero()).unwrap().0, account);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -226,9 +228,40 @@ mod tests {
|
|||||||
let thin_rlp = ::rlp::encode(&account);
|
let thin_rlp = ::rlp::encode(&account);
|
||||||
assert_eq!(::rlp::decode::<BasicAccount>(&thin_rlp), account);
|
assert_eq!(::rlp::decode::<BasicAccount>(&thin_rlp), account);
|
||||||
|
|
||||||
let fat_rlp = to_fat_rlp(&account, &AccountDB::new(db.as_hashdb(), &addr), &mut Default::default()).unwrap();
|
let fat_rlp = to_fat_rlps(&account, &AccountDB::new(db.as_hashdb(), &addr), &mut Default::default(), usize::max_value()).unwrap();
|
||||||
let fat_rlp = UntrustedRlp::new(&fat_rlp);
|
let fat_rlp = UntrustedRlp::new(&fat_rlp[0]);
|
||||||
assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp).unwrap().0, account);
|
assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp, H256::zero()).unwrap().0, account);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn encoding_storage_split() {
|
||||||
|
let mut db = get_temp_state_db();
|
||||||
|
let addr = Address::random();
|
||||||
|
|
||||||
|
let account = {
|
||||||
|
let acct_db = AccountDBMut::new(db.as_hashdb_mut(), &addr);
|
||||||
|
let mut root = SHA3_NULL_RLP;
|
||||||
|
fill_storage(acct_db, &mut root, &mut H256::zero());
|
||||||
|
BasicAccount {
|
||||||
|
nonce: 25.into(),
|
||||||
|
balance: 987654321.into(),
|
||||||
|
storage_root: root,
|
||||||
|
code_hash: SHA3_EMPTY,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let thin_rlp = ::rlp::encode(&account);
|
||||||
|
assert_eq!(::rlp::decode::<BasicAccount>(&thin_rlp), account);
|
||||||
|
|
||||||
|
let fat_rlps = to_fat_rlps(&account, &AccountDB::new(db.as_hashdb(), &addr), &mut Default::default(), 100).unwrap();
|
||||||
|
let mut root = SHA3_NULL_RLP;
|
||||||
|
let mut restored_account = None;
|
||||||
|
for rlp in fat_rlps {
|
||||||
|
let fat_rlp = UntrustedRlp::new(&rlp);
|
||||||
|
restored_account = Some(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr), fat_rlp, root).unwrap().0);
|
||||||
|
root = restored_account.as_ref().unwrap().storage_root.clone();
|
||||||
|
}
|
||||||
|
assert_eq!(restored_account, Some(account));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -264,18 +297,18 @@ mod tests {
|
|||||||
|
|
||||||
let mut used_code = HashSet::new();
|
let mut used_code = HashSet::new();
|
||||||
|
|
||||||
let fat_rlp1 = to_fat_rlp(&account1, &AccountDB::new(db.as_hashdb(), &addr1), &mut used_code).unwrap();
|
let fat_rlp1 = to_fat_rlps(&account1, &AccountDB::new(db.as_hashdb(), &addr1), &mut used_code, usize::max_value()).unwrap();
|
||||||
let fat_rlp2 = to_fat_rlp(&account2, &AccountDB::new(db.as_hashdb(), &addr2), &mut used_code).unwrap();
|
let fat_rlp2 = to_fat_rlps(&account2, &AccountDB::new(db.as_hashdb(), &addr2), &mut used_code, usize::max_value()).unwrap();
|
||||||
assert_eq!(used_code.len(), 1);
|
assert_eq!(used_code.len(), 1);
|
||||||
|
|
||||||
let fat_rlp1 = UntrustedRlp::new(&fat_rlp1);
|
let fat_rlp1 = UntrustedRlp::new(&fat_rlp1[0]);
|
||||||
let fat_rlp2 = UntrustedRlp::new(&fat_rlp2);
|
let fat_rlp2 = UntrustedRlp::new(&fat_rlp2[0]);
|
||||||
|
|
||||||
let (acc, maybe_code) = from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr2), fat_rlp2).unwrap();
|
let (acc, maybe_code) = from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr2), fat_rlp2, H256::zero()).unwrap();
|
||||||
assert!(maybe_code.is_none());
|
assert!(maybe_code.is_none());
|
||||||
assert_eq!(acc, account2);
|
assert_eq!(acc, account2);
|
||||||
|
|
||||||
let (acc, maybe_code) = from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr1), fat_rlp1).unwrap();
|
let (acc, maybe_code) = from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &addr1), fat_rlp1, H256::zero()).unwrap();
|
||||||
assert_eq!(maybe_code, Some(b"this is definitely code".to_vec()));
|
assert_eq!(maybe_code, Some(b"this is definitely code".to_vec()));
|
||||||
assert_eq!(acc, account1);
|
assert_eq!(acc, account1);
|
||||||
}
|
}
|
||||||
@@ -285,7 +318,7 @@ mod tests {
|
|||||||
let mut db = get_temp_state_db();
|
let mut db = get_temp_state_db();
|
||||||
let mut used_code = HashSet::new();
|
let mut used_code = HashSet::new();
|
||||||
|
|
||||||
assert_eq!(to_fat_rlp(&ACC_EMPTY, &AccountDB::new(db.as_hashdb(), &Address::default()), &mut used_code).unwrap(), ::rlp::NULL_RLP.to_vec());
|
assert_eq!(to_fat_rlps(&ACC_EMPTY, &AccountDB::new(db.as_hashdb(), &Address::default()), &mut used_code, usize::max_value()).unwrap(), vec![::rlp::NULL_RLP.to_vec()]);
|
||||||
assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &Address::default()), UntrustedRlp::new(&::rlp::NULL_RLP)).unwrap(), (ACC_EMPTY, None));
|
assert_eq!(from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &Address::default()), UntrustedRlp::new(&::rlp::NULL_RLP), H256::zero()).unwrap(), (ACC_EMPTY, None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ pub enum Error {
|
|||||||
Decoder(DecoderError),
|
Decoder(DecoderError),
|
||||||
/// Io error.
|
/// Io error.
|
||||||
Io(::std::io::Error),
|
Io(::std::io::Error),
|
||||||
|
/// Snapshot version is not supported.
|
||||||
|
VersionNotSupported(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
@@ -73,6 +75,7 @@ impl fmt::Display for Error {
|
|||||||
Error::Io(ref err) => err.fmt(f),
|
Error::Io(ref err) => err.fmt(f),
|
||||||
Error::Decoder(ref err) => err.fmt(f),
|
Error::Decoder(ref err) => err.fmt(f),
|
||||||
Error::Trie(ref err) => err.fmt(f),
|
Error::Trie(ref err) => err.fmt(f),
|
||||||
|
Error::VersionNotSupported(ref ver) => write!(f, "Snapshot version {} is not supprted.", ver),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ use rlp::{self, Encodable, RlpStream, UntrustedRlp, Stream, View};
|
|||||||
|
|
||||||
use super::ManifestData;
|
use super::ManifestData;
|
||||||
|
|
||||||
|
const SNAPSHOT_VERSION: u64 = 2;
|
||||||
|
|
||||||
/// Something which can write snapshots.
|
/// Something which can write snapshots.
|
||||||
/// Writing the same chunk multiple times will lead to implementation-defined
|
/// Writing the same chunk multiple times will lead to implementation-defined
|
||||||
/// behavior, and is not advised.
|
/// behavior, and is not advised.
|
||||||
@@ -120,8 +122,9 @@ impl SnapshotWriter for PackedWriter {
|
|||||||
fn finish(mut self, manifest: ManifestData) -> io::Result<()> {
|
fn finish(mut self, manifest: ManifestData) -> io::Result<()> {
|
||||||
// we ignore the hashes fields of the manifest under the assumption that
|
// we ignore the hashes fields of the manifest under the assumption that
|
||||||
// they are consistent with ours.
|
// they are consistent with ours.
|
||||||
let mut stream = RlpStream::new_list(5);
|
let mut stream = RlpStream::new_list(6);
|
||||||
stream
|
stream
|
||||||
|
.append(&SNAPSHOT_VERSION)
|
||||||
.append(&self.state_hashes)
|
.append(&self.state_hashes)
|
||||||
.append(&self.block_hashes)
|
.append(&self.block_hashes)
|
||||||
.append(&manifest.state_root)
|
.append(&manifest.state_root)
|
||||||
@@ -223,7 +226,7 @@ impl PackedReader {
|
|||||||
/// Create a new `PackedReader` for the file at the given path.
|
/// Create a new `PackedReader` for the file at the given path.
|
||||||
/// This will fail if any io errors are encountered or the file
|
/// This will fail if any io errors are encountered or the file
|
||||||
/// is not a valid packed snapshot.
|
/// is not a valid packed snapshot.
|
||||||
pub fn new(path: &Path) -> Result<Option<Self>, ::error::Error> {
|
pub fn new(path: &Path) -> Result<Option<Self>, ::snapshot::error::Error> {
|
||||||
let mut file = File::open(path)?;
|
let mut file = File::open(path)?;
|
||||||
let file_len = file.metadata()?.len();
|
let file_len = file.metadata()?.len();
|
||||||
if file_len < 8 {
|
if file_len < 8 {
|
||||||
@@ -257,15 +260,26 @@ impl PackedReader {
|
|||||||
|
|
||||||
let rlp = UntrustedRlp::new(&manifest_buf);
|
let rlp = UntrustedRlp::new(&manifest_buf);
|
||||||
|
|
||||||
let state: Vec<ChunkInfo> = rlp.val_at(0)?;
|
let (start, version) = if rlp.item_count() == 5 {
|
||||||
let blocks: Vec<ChunkInfo> = rlp.val_at(1)?;
|
(0, 1)
|
||||||
|
} else {
|
||||||
|
(1, rlp.val_at(0)?)
|
||||||
|
};
|
||||||
|
|
||||||
|
if version > SNAPSHOT_VERSION {
|
||||||
|
return Err(::snapshot::error::Error::VersionNotSupported(version));
|
||||||
|
}
|
||||||
|
|
||||||
|
let state: Vec<ChunkInfo> = rlp.val_at(0 + start)?;
|
||||||
|
let blocks: Vec<ChunkInfo> = rlp.val_at(1 + start)?;
|
||||||
|
|
||||||
let manifest = ManifestData {
|
let manifest = ManifestData {
|
||||||
|
version: version,
|
||||||
state_hashes: state.iter().map(|c| c.0).collect(),
|
state_hashes: state.iter().map(|c| c.0).collect(),
|
||||||
block_hashes: blocks.iter().map(|c| c.0).collect(),
|
block_hashes: blocks.iter().map(|c| c.0).collect(),
|
||||||
state_root: rlp.val_at(2)?,
|
state_root: rlp.val_at(2 + start)?,
|
||||||
block_number: rlp.val_at(3)?,
|
block_number: rlp.val_at(3 + start)?,
|
||||||
block_hash: rlp.val_at(4)?,
|
block_hash: rlp.val_at(4 + start)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Some(PackedReader {
|
Ok(Some(PackedReader {
|
||||||
@@ -348,7 +362,7 @@ mod tests {
|
|||||||
use util::sha3::Hashable;
|
use util::sha3::Hashable;
|
||||||
|
|
||||||
use snapshot::ManifestData;
|
use snapshot::ManifestData;
|
||||||
use super::{SnapshotWriter, SnapshotReader, PackedWriter, PackedReader, LooseWriter, LooseReader};
|
use super::{SnapshotWriter, SnapshotReader, PackedWriter, PackedReader, LooseWriter, LooseReader, SNAPSHOT_VERSION};
|
||||||
|
|
||||||
const STATE_CHUNKS: &'static [&'static [u8]] = &[b"dog", b"cat", b"hello world", b"hi", b"notarealchunk"];
|
const STATE_CHUNKS: &'static [&'static [u8]] = &[b"dog", b"cat", b"hello world", b"hi", b"notarealchunk"];
|
||||||
const BLOCK_CHUNKS: &'static [&'static [u8]] = &[b"hello!", b"goodbye!", b"abcdefg", b"hijklmnop", b"qrstuvwxy", b"and", b"z"];
|
const BLOCK_CHUNKS: &'static [&'static [u8]] = &[b"hello!", b"goodbye!", b"abcdefg", b"hijklmnop", b"qrstuvwxy", b"and", b"z"];
|
||||||
@@ -374,6 +388,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let manifest = ManifestData {
|
let manifest = ManifestData {
|
||||||
|
version: SNAPSHOT_VERSION,
|
||||||
state_hashes: state_hashes,
|
state_hashes: state_hashes,
|
||||||
block_hashes: block_hashes,
|
block_hashes: block_hashes,
|
||||||
state_root: b"notarealroot".sha3(),
|
state_root: b"notarealroot".sha3(),
|
||||||
@@ -412,6 +427,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let manifest = ManifestData {
|
let manifest = ManifestData {
|
||||||
|
version: SNAPSHOT_VERSION,
|
||||||
state_hashes: state_hashes,
|
state_hashes: state_hashes,
|
||||||
block_hashes: block_hashes,
|
block_hashes: block_hashes,
|
||||||
state_root: b"notarealroot".sha3(),
|
state_root: b"notarealroot".sha3(),
|
||||||
@@ -428,4 +444,4 @@ mod tests {
|
|||||||
reader.chunk(hash.clone()).unwrap();
|
reader.chunk(hash.clone()).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ pub use self::traits::SnapshotService;
|
|||||||
pub use self::watcher::Watcher;
|
pub use self::watcher::Watcher;
|
||||||
pub use types::snapshot_manifest::ManifestData;
|
pub use types::snapshot_manifest::ManifestData;
|
||||||
pub use types::restoration_status::RestorationStatus;
|
pub use types::restoration_status::RestorationStatus;
|
||||||
|
pub use types::basic_account::BasicAccount;
|
||||||
|
|
||||||
pub mod io;
|
pub mod io;
|
||||||
pub mod service;
|
pub mod service;
|
||||||
@@ -82,6 +83,9 @@ mod traits {
|
|||||||
// Try to have chunks be around 4MB (before compression)
|
// Try to have chunks be around 4MB (before compression)
|
||||||
const PREFERRED_CHUNK_SIZE: usize = 4 * 1024 * 1024;
|
const PREFERRED_CHUNK_SIZE: usize = 4 * 1024 * 1024;
|
||||||
|
|
||||||
|
// Try to have chunks be around 4MB (before compression)
|
||||||
|
const MAX_STORAGE_ENTRIES_PER_ACCOUNT_RECORD: usize = 80_000;
|
||||||
|
|
||||||
// How many blocks to include in a snapshot, starting from the head of the chain.
|
// How many blocks to include in a snapshot, starting from the head of the chain.
|
||||||
const SNAPSHOT_BLOCKS: u64 = 30000;
|
const SNAPSHOT_BLOCKS: u64 = 30000;
|
||||||
|
|
||||||
@@ -147,6 +151,7 @@ pub fn take_snapshot<W: SnapshotWriter + Send>(
|
|||||||
info!("produced {} state chunks and {} block chunks.", state_hashes.len(), block_hashes.len());
|
info!("produced {} state chunks and {} block chunks.", state_hashes.len(), block_hashes.len());
|
||||||
|
|
||||||
let manifest_data = ManifestData {
|
let manifest_data = ManifestData {
|
||||||
|
version: 2,
|
||||||
state_hashes: state_hashes,
|
state_hashes: state_hashes,
|
||||||
block_hashes: block_hashes,
|
block_hashes: block_hashes,
|
||||||
state_root: *state_root,
|
state_root: *state_root,
|
||||||
@@ -300,14 +305,14 @@ impl<'a> StateChunker<'a> {
|
|||||||
//
|
//
|
||||||
// If the buffer is greater than the desired chunk size,
|
// If the buffer is greater than the desired chunk size,
|
||||||
// this will write out the data to disk.
|
// this will write out the data to disk.
|
||||||
fn push(&mut self, account_hash: Bytes, data: Bytes) -> Result<(), Error> {
|
fn push(&mut self, account_hash: Bytes, data: Bytes, force_chunk: bool) -> Result<(), Error> {
|
||||||
let pair = {
|
let pair = {
|
||||||
let mut stream = RlpStream::new_list(2);
|
let mut stream = RlpStream::new_list(2);
|
||||||
stream.append(&account_hash).append_raw(&data, 1);
|
stream.append(&account_hash).append_raw(&data, 1);
|
||||||
stream.out()
|
stream.out()
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.cur_size + pair.len() >= PREFERRED_CHUNK_SIZE {
|
if force_chunk || self.cur_size + pair.len() >= PREFERRED_CHUNK_SIZE {
|
||||||
self.write_chunk()?;
|
self.write_chunk()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,8 +377,10 @@ pub fn chunk_state<'a>(db: &HashDB, root: &H256, writer: &Mutex<SnapshotWriter +
|
|||||||
|
|
||||||
let account_db = AccountDB::from_hash(db, account_key_hash);
|
let account_db = AccountDB::from_hash(db, account_key_hash);
|
||||||
|
|
||||||
let fat_rlp = account::to_fat_rlp(&account, &account_db, &mut used_code)?;
|
let fat_rlps = account::to_fat_rlps(&account, &account_db, &mut used_code, MAX_STORAGE_ENTRIES_PER_ACCOUNT_RECORD)?;
|
||||||
chunker.push(account_key, fat_rlp)?;
|
for (i, fat_rlp) in fat_rlps.into_iter().enumerate() {
|
||||||
|
chunker.push(account_key.clone(), fat_rlp, i > 0)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if chunker.cur_size != 0 {
|
if chunker.cur_size != 0 {
|
||||||
@@ -390,6 +397,7 @@ pub struct StateRebuilder {
|
|||||||
known_code: HashMap<H256, H256>, // code hashes mapped to first account with this code.
|
known_code: HashMap<H256, H256>, // code hashes mapped to first account with this code.
|
||||||
missing_code: HashMap<H256, Vec<H256>>, // maps code hashes to lists of accounts missing that code.
|
missing_code: HashMap<H256, Vec<H256>>, // maps code hashes to lists of accounts missing that code.
|
||||||
bloom: Bloom,
|
bloom: Bloom,
|
||||||
|
known_storage_roots: HashMap<H256, H256>, // maps account hashes to last known storage root. Only filled for last account per chunk.
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StateRebuilder {
|
impl StateRebuilder {
|
||||||
@@ -401,6 +409,7 @@ impl StateRebuilder {
|
|||||||
known_code: HashMap::new(),
|
known_code: HashMap::new(),
|
||||||
missing_code: HashMap::new(),
|
missing_code: HashMap::new(),
|
||||||
bloom: StateDB::load_bloom(&*db),
|
bloom: StateDB::load_bloom(&*db),
|
||||||
|
known_storage_roots: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,6 +427,7 @@ impl StateRebuilder {
|
|||||||
rlp,
|
rlp,
|
||||||
&mut pairs,
|
&mut pairs,
|
||||||
&self.known_code,
|
&self.known_code,
|
||||||
|
&mut self.known_storage_roots,
|
||||||
flag
|
flag
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@@ -464,14 +474,18 @@ impl StateRebuilder {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check for accounts missing code. Once all chunks have been fed, there should
|
/// Finalize the restoration. Check for accounts missing code and make a dummy
|
||||||
/// be none.
|
/// journal entry.
|
||||||
pub fn check_missing(self) -> Result<(), Error> {
|
/// Once all chunks have been fed, there should be nothing missing.
|
||||||
|
pub fn finalize(mut self, era: u64, id: H256) -> Result<(), ::error::Error> {
|
||||||
let missing = self.missing_code.keys().cloned().collect::<Vec<_>>();
|
let missing = self.missing_code.keys().cloned().collect::<Vec<_>>();
|
||||||
match missing.is_empty() {
|
if !missing.is_empty() { return Err(Error::MissingCode(missing).into()) }
|
||||||
true => Ok(()),
|
|
||||||
false => Err(Error::MissingCode(missing)),
|
let mut batch = self.db.backing().transaction();
|
||||||
}
|
self.db.journal_under(&mut batch, era, &id)?;
|
||||||
|
self.db.backing().write_buffered(batch);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the state root of the rebuilder.
|
/// Get the state root of the rebuilder.
|
||||||
@@ -492,10 +506,11 @@ fn rebuild_accounts(
|
|||||||
account_fat_rlps: UntrustedRlp,
|
account_fat_rlps: UntrustedRlp,
|
||||||
out_chunk: &mut [(H256, Bytes)],
|
out_chunk: &mut [(H256, Bytes)],
|
||||||
known_code: &HashMap<H256, H256>,
|
known_code: &HashMap<H256, H256>,
|
||||||
|
known_storage_roots: &mut HashMap<H256, H256>,
|
||||||
abort_flag: &AtomicBool,
|
abort_flag: &AtomicBool,
|
||||||
) -> Result<RebuiltStatus, ::error::Error> {
|
) -> Result<RebuiltStatus, ::error::Error> {
|
||||||
let mut status = RebuiltStatus::default();
|
let mut status = RebuiltStatus::default();
|
||||||
for (account_rlp, out) in account_fat_rlps.into_iter().zip(out_chunk) {
|
for (account_rlp, out) in account_fat_rlps.into_iter().zip(out_chunk.iter_mut()) {
|
||||||
if !abort_flag.load(Ordering::SeqCst) { return Err(Error::RestorationAborted.into()) }
|
if !abort_flag.load(Ordering::SeqCst) { return Err(Error::RestorationAborted.into()) }
|
||||||
|
|
||||||
let hash: H256 = account_rlp.val_at(0)?;
|
let hash: H256 = account_rlp.val_at(0)?;
|
||||||
@@ -506,7 +521,8 @@ fn rebuild_accounts(
|
|||||||
// fill out the storage trie and code while decoding.
|
// fill out the storage trie and code while decoding.
|
||||||
let (acc, maybe_code) = {
|
let (acc, maybe_code) = {
|
||||||
let mut acct_db = AccountDBMut::from_hash(db, hash);
|
let mut acct_db = AccountDBMut::from_hash(db, hash);
|
||||||
account::from_fat_rlp(&mut acct_db, fat_rlp)?
|
let storage_root = known_storage_roots.get(&hash).cloned().unwrap_or(H256::zero());
|
||||||
|
account::from_fat_rlp(&mut acct_db, fat_rlp, storage_root)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let code_hash = acc.code_hash.clone();
|
let code_hash = acc.code_hash.clone();
|
||||||
@@ -538,6 +554,12 @@ fn rebuild_accounts(
|
|||||||
|
|
||||||
*out = (hash, thin_rlp);
|
*out = (hash, thin_rlp);
|
||||||
}
|
}
|
||||||
|
if let Some(&(ref hash, ref rlp)) = out_chunk.iter().last() {
|
||||||
|
known_storage_roots.insert(*hash, ::rlp::decode::<BasicAccount>(rlp).storage_root);
|
||||||
|
}
|
||||||
|
if let Some(&(ref hash, ref rlp)) = out_chunk.iter().next() {
|
||||||
|
known_storage_roots.insert(*hash, ::rlp::decode::<BasicAccount>(rlp).storage_root);
|
||||||
|
}
|
||||||
Ok(status)
|
Ok(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ impl Restoration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check for missing code.
|
// check for missing code.
|
||||||
self.state.check_missing()?;
|
self.state.finalize(self.manifest.block_number, self.manifest.block_hash)?;
|
||||||
|
|
||||||
// connect out-of-order chunks and verify chain integrity.
|
// connect out-of-order chunks and verify chain integrity.
|
||||||
self.blocks.finalize(self.canonical_hashes)?;
|
self.blocks.finalize(self.canonical_hashes)?;
|
||||||
@@ -656,6 +656,7 @@ mod tests {
|
|||||||
assert_eq!(service.status(), RestorationStatus::Inactive);
|
assert_eq!(service.status(), RestorationStatus::Inactive);
|
||||||
|
|
||||||
let manifest = ManifestData {
|
let manifest = ManifestData {
|
||||||
|
version: 2,
|
||||||
state_hashes: vec![],
|
state_hashes: vec![],
|
||||||
block_hashes: vec![],
|
block_hashes: vec![],
|
||||||
state_root: Default::default(),
|
state_root: Default::default(),
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ fn chunk_and_restore(amount: u64) {
|
|||||||
let writer = Mutex::new(PackedWriter::new(&snapshot_path).unwrap());
|
let writer = Mutex::new(PackedWriter::new(&snapshot_path).unwrap());
|
||||||
let block_hashes = chunk_blocks(&bc, best_hash, &writer, &Progress::default()).unwrap();
|
let block_hashes = chunk_blocks(&bc, best_hash, &writer, &Progress::default()).unwrap();
|
||||||
let manifest = ::snapshot::ManifestData {
|
let manifest = ::snapshot::ManifestData {
|
||||||
|
version: 2,
|
||||||
state_hashes: Vec::new(),
|
state_hashes: Vec::new(),
|
||||||
block_hashes: block_hashes,
|
block_hashes: block_hashes,
|
||||||
state_root: ::util::sha3::SHA3_NULL_RLP,
|
state_root: ::util::sha3::SHA3_NULL_RLP,
|
||||||
@@ -125,6 +126,7 @@ fn checks_flag() {
|
|||||||
let chain = BlockChain::new(Default::default(), &genesis, db.clone());
|
let chain = BlockChain::new(Default::default(), &genesis, db.clone());
|
||||||
|
|
||||||
let manifest = ::snapshot::ManifestData {
|
let manifest = ::snapshot::ManifestData {
|
||||||
|
version: 2,
|
||||||
state_hashes: Vec::new(),
|
state_hashes: Vec::new(),
|
||||||
block_hashes: Vec::new(),
|
block_hashes: Vec::new(),
|
||||||
state_root: ::util::sha3::SHA3_NULL_RLP,
|
state_root: ::util::sha3::SHA3_NULL_RLP,
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ use super::ManifestData;
|
|||||||
#[test]
|
#[test]
|
||||||
fn manifest_rlp() {
|
fn manifest_rlp() {
|
||||||
let manifest = ManifestData {
|
let manifest = ManifestData {
|
||||||
|
version: 2,
|
||||||
block_hashes: Vec::new(),
|
block_hashes: Vec::new(),
|
||||||
state_hashes: Vec::new(),
|
state_hashes: Vec::new(),
|
||||||
block_number: 1234567,
|
block_number: 1234567,
|
||||||
@@ -35,4 +36,4 @@ fn manifest_rlp() {
|
|||||||
};
|
};
|
||||||
let raw = manifest.clone().into_rlp();
|
let raw = manifest.clone().into_rlp();
|
||||||
assert_eq!(ManifestData::from_rlp(&raw).unwrap(), manifest);
|
assert_eq!(ManifestData::from_rlp(&raw).unwrap(), manifest);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ fn guards_delete_folders() {
|
|||||||
path.push("restoration");
|
path.push("restoration");
|
||||||
|
|
||||||
let manifest = ManifestData {
|
let manifest = ManifestData {
|
||||||
|
version: 2,
|
||||||
state_hashes: vec![],
|
state_hashes: vec![],
|
||||||
block_hashes: vec![],
|
block_hashes: vec![],
|
||||||
block_number: 0,
|
block_number: 0,
|
||||||
|
|||||||
@@ -58,10 +58,11 @@ fn snap_and_restore() {
|
|||||||
let state_hashes = chunk_state(&old_db, &state_root, &writer, &Progress::default()).unwrap();
|
let state_hashes = chunk_state(&old_db, &state_root, &writer, &Progress::default()).unwrap();
|
||||||
|
|
||||||
writer.into_inner().finish(::snapshot::ManifestData {
|
writer.into_inner().finish(::snapshot::ManifestData {
|
||||||
|
version: 2,
|
||||||
state_hashes: state_hashes,
|
state_hashes: state_hashes,
|
||||||
block_hashes: Vec::new(),
|
block_hashes: Vec::new(),
|
||||||
state_root: state_root,
|
state_root: state_root,
|
||||||
block_number: 0,
|
block_number: 1000,
|
||||||
block_hash: H256::default(),
|
block_hash: H256::default(),
|
||||||
}).unwrap();
|
}).unwrap();
|
||||||
|
|
||||||
@@ -69,7 +70,7 @@ fn snap_and_restore() {
|
|||||||
db_path.push("db");
|
db_path.push("db");
|
||||||
let db = {
|
let db = {
|
||||||
let new_db = Arc::new(Database::open(&db_cfg, &db_path.to_string_lossy()).unwrap());
|
let new_db = Arc::new(Database::open(&db_cfg, &db_path.to_string_lossy()).unwrap());
|
||||||
let mut rebuilder = StateRebuilder::new(new_db.clone(), Algorithm::Archive);
|
let mut rebuilder = StateRebuilder::new(new_db.clone(), Algorithm::OverlayRecent);
|
||||||
let reader = PackedReader::new(&snap_file).unwrap().unwrap();
|
let reader = PackedReader::new(&snap_file).unwrap().unwrap();
|
||||||
|
|
||||||
let flag = AtomicBool::new(true);
|
let flag = AtomicBool::new(true);
|
||||||
@@ -82,12 +83,13 @@ fn snap_and_restore() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(rebuilder.state_root(), state_root);
|
assert_eq!(rebuilder.state_root(), state_root);
|
||||||
rebuilder.check_missing().unwrap();
|
rebuilder.finalize(1000, H256::default()).unwrap();
|
||||||
|
|
||||||
new_db
|
new_db
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_db = journaldb::new(db, Algorithm::Archive, ::db::COL_STATE);
|
let new_db = journaldb::new(db, Algorithm::OverlayRecent, ::db::COL_STATE);
|
||||||
|
assert_eq!(new_db.earliest_era(), Some(1000));
|
||||||
|
|
||||||
compare_dbs(&old_db, new_db.as_hashdb());
|
compare_dbs(&old_db, new_db.as_hashdb());
|
||||||
}
|
}
|
||||||
@@ -120,10 +122,10 @@ fn get_code_from_prev_chunk() {
|
|||||||
let mut db = MemoryDB::new();
|
let mut db = MemoryDB::new();
|
||||||
AccountDBMut::from_hash(&mut db, hash).insert(&code[..]);
|
AccountDBMut::from_hash(&mut db, hash).insert(&code[..]);
|
||||||
|
|
||||||
let fat_rlp = account::to_fat_rlp(&acc, &AccountDB::from_hash(&db, hash), &mut used_code).unwrap();
|
let fat_rlp = account::to_fat_rlps(&acc, &AccountDB::from_hash(&db, hash), &mut used_code, usize::max_value()).unwrap();
|
||||||
|
|
||||||
let mut stream = RlpStream::new_list(1);
|
let mut stream = RlpStream::new_list(1);
|
||||||
stream.begin_list(2).append(&hash).append_raw(&fat_rlp, 1);
|
stream.begin_list(2).append(&hash).append_raw(&fat_rlp[0], 1);
|
||||||
stream.out()
|
stream.out()
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -134,13 +136,18 @@ fn get_code_from_prev_chunk() {
|
|||||||
let db_cfg = DatabaseConfig::with_columns(::db::NUM_COLUMNS);
|
let db_cfg = DatabaseConfig::with_columns(::db::NUM_COLUMNS);
|
||||||
let new_db = Arc::new(Database::open(&db_cfg, &db_path.to_string_lossy()).unwrap());
|
let new_db = Arc::new(Database::open(&db_cfg, &db_path.to_string_lossy()).unwrap());
|
||||||
|
|
||||||
let mut rebuilder = StateRebuilder::new(new_db, Algorithm::Archive);
|
{
|
||||||
let flag = AtomicBool::new(true);
|
let mut rebuilder = StateRebuilder::new(new_db.clone(), Algorithm::OverlayRecent);
|
||||||
|
let flag = AtomicBool::new(true);
|
||||||
|
|
||||||
rebuilder.feed(&chunk1, &flag).unwrap();
|
rebuilder.feed(&chunk1, &flag).unwrap();
|
||||||
rebuilder.feed(&chunk2, &flag).unwrap();
|
rebuilder.feed(&chunk2, &flag).unwrap();
|
||||||
|
|
||||||
rebuilder.check_missing().unwrap();
|
rebuilder.finalize(1000, H256::random()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let state_db = journaldb::new(new_db, Algorithm::OverlayRecent, ::db::COL_STATE);
|
||||||
|
assert_eq!(state_db.earliest_era(), Some(1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -164,6 +171,7 @@ fn checks_flag() {
|
|||||||
let state_hashes = chunk_state(&old_db, &state_root, &writer, &Progress::default()).unwrap();
|
let state_hashes = chunk_state(&old_db, &state_root, &writer, &Progress::default()).unwrap();
|
||||||
|
|
||||||
writer.into_inner().finish(::snapshot::ManifestData {
|
writer.into_inner().finish(::snapshot::ManifestData {
|
||||||
|
version: 2,
|
||||||
state_hashes: state_hashes,
|
state_hashes: state_hashes,
|
||||||
block_hashes: Vec::new(),
|
block_hashes: Vec::new(),
|
||||||
state_root: state_root,
|
state_root: state_root,
|
||||||
@@ -175,7 +183,7 @@ fn checks_flag() {
|
|||||||
db_path.push("db");
|
db_path.push("db");
|
||||||
{
|
{
|
||||||
let new_db = Arc::new(Database::open(&db_cfg, &db_path.to_string_lossy()).unwrap());
|
let new_db = Arc::new(Database::open(&db_cfg, &db_path.to_string_lossy()).unwrap());
|
||||||
let mut rebuilder = StateRebuilder::new(new_db.clone(), Algorithm::Archive);
|
let mut rebuilder = StateRebuilder::new(new_db.clone(), Algorithm::OverlayRecent);
|
||||||
let reader = PackedReader::new(&snap_file).unwrap().unwrap();
|
let reader = PackedReader::new(&snap_file).unwrap().unwrap();
|
||||||
|
|
||||||
let flag = AtomicBool::new(false);
|
let flag = AtomicBool::new(false);
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ pub struct CommonParams {
|
|||||||
pub fork_block: Option<(BlockNumber, H256)>,
|
pub fork_block: Option<(BlockNumber, H256)>,
|
||||||
/// Number of first block where EIP-98 rules begin.
|
/// Number of first block where EIP-98 rules begin.
|
||||||
pub eip98_transition: BlockNumber,
|
pub eip98_transition: BlockNumber,
|
||||||
|
/// Validate block receipts root.
|
||||||
|
pub validate_receipts_transition: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ethjson::spec::Params> for CommonParams {
|
impl From<ethjson::spec::Params> for CommonParams {
|
||||||
@@ -68,6 +70,7 @@ impl From<ethjson::spec::Params> for CommonParams {
|
|||||||
min_gas_limit: p.min_gas_limit.into(),
|
min_gas_limit: p.min_gas_limit.into(),
|
||||||
fork_block: if let (Some(n), Some(h)) = (p.fork_block, p.fork_hash) { Some((n.into(), h.into())) } else { None },
|
fork_block: if let (Some(n), Some(h)) = (p.fork_block, p.fork_hash) { Some((n.into(), h.into())) } else { None },
|
||||||
eip98_transition: p.eip98_transition.map_or(0, Into::into),
|
eip98_transition: p.eip98_transition.map_or(0, Into::into),
|
||||||
|
validate_receipts_transition: p.validate_receipts_transition.map_or(0, Into::into),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -357,6 +360,10 @@ impl Spec {
|
|||||||
/// Account is marked with `reportBenign` it can be checked as disliked with "0xd8f2e0bf".
|
/// Account is marked with `reportBenign` it can be checked as disliked with "0xd8f2e0bf".
|
||||||
/// Validator can be removed with `reportMalicious`.
|
/// Validator can be removed with `reportMalicious`.
|
||||||
pub fn new_validator_contract() -> Self { load_bundled!("validator_contract") }
|
pub fn new_validator_contract() -> Self { load_bundled!("validator_contract") }
|
||||||
|
|
||||||
|
/// Create a new Spec with BasicAuthority which uses multiple validator sets changing with height.
|
||||||
|
/// Account with secrets "0".sha3() is the validator for block 1 and with "1".sha3() onwards.
|
||||||
|
pub fn new_validator_multi() -> Self { load_bundled!("validator_multi") }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -546,7 +546,7 @@ impl<B: Backend> State<B> {
|
|||||||
|
|
||||||
// TODO uncomment once to_pod() works correctly.
|
// TODO uncomment once to_pod() works correctly.
|
||||||
// trace!("Applied transaction. Diff:\n{}\n", state_diff::diff_pod(&old, &self.to_pod()));
|
// trace!("Applied transaction. Diff:\n{}\n", state_diff::diff_pod(&old, &self.to_pod()));
|
||||||
let state_root = if env_info.number < engine.params().eip98_transition {
|
let state_root = if env_info.number < engine.params().eip98_transition || env_info.number < engine.params().validate_receipts_transition {
|
||||||
self.commit()?;
|
self.commit()?;
|
||||||
Some(self.root().clone())
|
Some(self.root().clone())
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -455,6 +455,7 @@ pub fn get_default_ethash_params() -> EthashParams{
|
|||||||
eip161d_transition: u64::max_value(),
|
eip161d_transition: u64::max_value(),
|
||||||
ecip1010_pause_transition: u64::max_value(),
|
ecip1010_pause_transition: u64::max_value(),
|
||||||
ecip1010_continue_transition: u64::max_value(),
|
ecip1010_continue_transition: u64::max_value(),
|
||||||
|
ecip1017_era_rounds: u64::max_value(),
|
||||||
max_code_size: u64::max_value(),
|
max_code_size: u64::max_value(),
|
||||||
max_gas_limit_transition: u64::max_value(),
|
max_gas_limit_transition: u64::max_value(),
|
||||||
max_gas_limit: U256::max_value(),
|
max_gas_limit: U256::max_value(),
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ use util::Bytes;
|
|||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "ipc", binary)]
|
#[cfg_attr(feature = "ipc", binary)]
|
||||||
pub struct ManifestData {
|
pub struct ManifestData {
|
||||||
|
/// Snapshot format version.
|
||||||
|
pub version: u64,
|
||||||
/// List of state chunk hashes.
|
/// List of state chunk hashes.
|
||||||
pub state_hashes: Vec<H256>,
|
pub state_hashes: Vec<H256>,
|
||||||
/// List of block chunk hashes.
|
/// List of block chunk hashes.
|
||||||
@@ -39,7 +41,8 @@ pub struct ManifestData {
|
|||||||
impl ManifestData {
|
impl ManifestData {
|
||||||
/// Encode the manifest data to rlp.
|
/// Encode the manifest data to rlp.
|
||||||
pub fn into_rlp(self) -> Bytes {
|
pub fn into_rlp(self) -> Bytes {
|
||||||
let mut stream = RlpStream::new_list(5);
|
let mut stream = RlpStream::new_list(6);
|
||||||
|
stream.append(&self.version);
|
||||||
stream.append(&self.state_hashes);
|
stream.append(&self.state_hashes);
|
||||||
stream.append(&self.block_hashes);
|
stream.append(&self.block_hashes);
|
||||||
stream.append(&self.state_root);
|
stream.append(&self.state_root);
|
||||||
@@ -52,14 +55,20 @@ impl ManifestData {
|
|||||||
/// Try to restore manifest data from raw bytes, interpreted as RLP.
|
/// Try to restore manifest data from raw bytes, interpreted as RLP.
|
||||||
pub fn from_rlp(raw: &[u8]) -> Result<Self, DecoderError> {
|
pub fn from_rlp(raw: &[u8]) -> Result<Self, DecoderError> {
|
||||||
let decoder = UntrustedRlp::new(raw);
|
let decoder = UntrustedRlp::new(raw);
|
||||||
|
let (start, version) = if decoder.item_count() == 5 {
|
||||||
|
(0, 1)
|
||||||
|
} else {
|
||||||
|
(1, decoder.val_at(0)?)
|
||||||
|
};
|
||||||
|
|
||||||
let state_hashes: Vec<H256> = decoder.val_at(0)?;
|
let state_hashes: Vec<H256> = decoder.val_at(start + 0)?;
|
||||||
let block_hashes: Vec<H256> = decoder.val_at(1)?;
|
let block_hashes: Vec<H256> = decoder.val_at(start + 1)?;
|
||||||
let state_root: H256 = decoder.val_at(2)?;
|
let state_root: H256 = decoder.val_at(start + 2)?;
|
||||||
let block_number: u64 = decoder.val_at(3)?;
|
let block_number: u64 = decoder.val_at(start + 3)?;
|
||||||
let block_hash: H256 = decoder.val_at(4)?;
|
let block_hash: H256 = decoder.val_at(start + 4)?;
|
||||||
|
|
||||||
Ok(ManifestData {
|
Ok(ManifestData {
|
||||||
|
version: version,
|
||||||
state_hashes: state_hashes,
|
state_hashes: state_hashes,
|
||||||
block_hashes: block_hashes,
|
block_hashes: block_hashes,
|
||||||
state_root: state_root,
|
state_root: state_root,
|
||||||
|
|||||||
@@ -124,12 +124,17 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut verified = HashSet::new();
|
||||||
for uncle in UntrustedRlp::new(bytes).at(2)?.iter().map(|rlp| rlp.as_val::<Header>()) {
|
for uncle in UntrustedRlp::new(bytes).at(2)?.iter().map(|rlp| rlp.as_val::<Header>()) {
|
||||||
let uncle = uncle?;
|
let uncle = uncle?;
|
||||||
if excluded.contains(&uncle.hash()) {
|
if excluded.contains(&uncle.hash()) {
|
||||||
return Err(From::from(BlockError::UncleInChain(uncle.hash())))
|
return Err(From::from(BlockError::UncleInChain(uncle.hash())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if verified.contains(&uncle.hash()) {
|
||||||
|
return Err(From::from(BlockError::DuplicateUncle(uncle.hash())))
|
||||||
|
}
|
||||||
|
|
||||||
// m_currentBlock.number() - uncle.number() m_cB.n - uP.n()
|
// m_currentBlock.number() - uncle.number() m_cB.n - uP.n()
|
||||||
// 1 2
|
// 1 2
|
||||||
// 2
|
// 2
|
||||||
@@ -172,6 +177,7 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &
|
|||||||
|
|
||||||
verify_parent(&uncle, &uncle_parent)?;
|
verify_parent(&uncle, &uncle_parent)?;
|
||||||
engine.verify_block_family(&uncle, &uncle_parent, Some(bytes))?;
|
engine.verify_block_family(&uncle, &uncle_parent, Some(bytes))?;
|
||||||
|
verified.insert(uncle.hash());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -555,6 +561,11 @@ mod tests {
|
|||||||
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &bad_uncles), engine, &bc),
|
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &bad_uncles), engine, &bc),
|
||||||
TooManyUncles(OutOfBounds { max: Some(engine.maximum_uncle_count()), min: None, found: bad_uncles.len() }));
|
TooManyUncles(OutOfBounds { max: Some(engine.maximum_uncle_count()), min: None, found: bad_uncles.len() }));
|
||||||
|
|
||||||
|
header = good.clone();
|
||||||
|
bad_uncles = vec![ good_uncle1.clone(), good_uncle1.clone() ];
|
||||||
|
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &bad_uncles), engine, &bc),
|
||||||
|
DuplicateUncle(good_uncle1.hash()));
|
||||||
|
|
||||||
// TODO: some additional uncle checks
|
// TODO: some additional uncle checks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rust-crypto = "0.2.36"
|
rust-crypto = "0.2.36"
|
||||||
tiny-keccak = "1.0"
|
tiny-keccak = "1.2"
|
||||||
eth-secp256k1 = { git = "https://github.com/ethcore/rust-secp256k1" }
|
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" }
|
||||||
ethkey = { path = "../ethkey" }
|
ethkey = { path = "../ethkey" }
|
||||||
ethcore-bigint = { path = "../util/bigint" }
|
ethcore-bigint = { path = "../util/bigint" }
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "0.3.14"
|
rand = "0.3.14"
|
||||||
lazy_static = "0.2"
|
lazy_static = "0.2"
|
||||||
tiny-keccak = "1.0"
|
tiny-keccak = "1.2"
|
||||||
eth-secp256k1 = { git = "https://github.com/ethcore/rust-secp256k1" }
|
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" }
|
||||||
rustc-serialize = "0.3"
|
rustc-serialize = "0.3"
|
||||||
docopt = { version = "0.6", optional = true }
|
docopt = { version = "0.6", optional = true }
|
||||||
ethcore-bigint = { path = "../util/bigint" }
|
ethcore-bigint = { path = "../util/bigint" }
|
||||||
|
|||||||
@@ -57,8 +57,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_brain() {
|
fn test_brain() {
|
||||||
let words = "this is sparta!".to_owned();
|
let words = "this is sparta!".to_owned();
|
||||||
let first_keypair = Brain(words.clone()).generate().unwrap();
|
let first_keypair = Brain::new(words.clone()).generate().unwrap();
|
||||||
let second_keypair = Brain(words.clone()).generate().unwrap();
|
let second_keypair = Brain::new(words.clone()).generate().unwrap();
|
||||||
assert_eq!(first_keypair.secret(), second_keypair.secret());
|
assert_eq!(first_keypair.secret(), second_keypair.secret());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ serde_json = "0.9"
|
|||||||
serde_derive = "0.9"
|
serde_derive = "0.9"
|
||||||
rustc-serialize = "0.3"
|
rustc-serialize = "0.3"
|
||||||
rust-crypto = "0.2.36"
|
rust-crypto = "0.2.36"
|
||||||
tiny-keccak = "1.0"
|
tiny-keccak = "1.2"
|
||||||
docopt = { version = "0.6", optional = true }
|
docopt = { version = "0.6", optional = true }
|
||||||
time = "0.1.34"
|
time = "0.1.34"
|
||||||
lazy_static = "0.2"
|
lazy_static = "0.2"
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ version = "0.1.0"
|
|||||||
authors = ["Parity Technologies <admin@parity.io>"]
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "evm"
|
name = "evmbin"
|
||||||
path = "./src/main.rs"
|
path = "./src/main.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "evm"
|
name = "parity-evm"
|
||||||
path = "./src/main.rs"
|
path = "./src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@@ -7,4 +7,4 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
|||||||
crate-type = ["dylib"]
|
crate-type = ["dylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tiny-keccak = "1.0"
|
tiny-keccak = "1.2"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ version = "1.6.0"
|
|||||||
authors = ["Parity Technologies <admin@parity.io>"]
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ethabi = "1.0.0"
|
ethabi = "1.0"
|
||||||
futures = "0.1"
|
futures = "0.1"
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
mime = "0.2"
|
mime = "0.2"
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
parking_lot = "0.3"
|
parking_lot = "0.3"
|
||||||
hidapi = { git = "https://github.com/ethcore/hidapi-rs" }
|
hidapi = { git = "https://github.com/paritytech/hidapi-rs" }
|
||||||
libusb = { git = "https://github.com/ethcore/libusb-rs" }
|
libusb = { git = "https://github.com/paritytech/libusb-rs" }
|
||||||
ethkey = { path = "../ethkey" }
|
ethkey = { path = "../ethkey" }
|
||||||
ethcore-bigint = { path = "../util/bigint" }
|
ethcore-bigint = { path = "../util/bigint" }
|
||||||
|
|
||||||
|
|||||||
@@ -271,7 +271,7 @@ impl Manager {
|
|||||||
chunk_size += size;
|
chunk_size += size;
|
||||||
}
|
}
|
||||||
trace!("writing {:?}", &hid_chunk[..]);
|
trace!("writing {:?}", &hid_chunk[..]);
|
||||||
let n = handle.write(&hid_chunk[0..chunk_size])?;
|
let n = handle.write(&hid_chunk[..])?;
|
||||||
if n < chunk_size {
|
if n < chunk_size {
|
||||||
return Err(Error::Protocol("Write data size mismatch"));
|
return Err(Error::Protocol("Write data size mismatch"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,13 +14,13 @@ nightly-testing = ["clippy"]
|
|||||||
with-syntex = ["quasi/with-syntex", "quasi_codegen", "quasi_codegen/with-syntex", "syntex", "syntex_syntax"]
|
with-syntex = ["quasi/with-syntex", "quasi_codegen", "quasi_codegen/with-syntex", "syntex", "syntex_syntax"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
quasi_codegen = { version = "0.11", optional = true }
|
quasi_codegen = { version = "0.32", optional = true }
|
||||||
syntex = { version = "0.33", optional = true }
|
syntex = { version = "0.58", optional = true }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
aster = { version = "0.17", default-features = false }
|
aster = { version = "0.41", default-features = false }
|
||||||
clippy = { version = "^0.*", optional = true }
|
clippy = { version = "^0.*", optional = true }
|
||||||
quasi = { version = "0.11", default-features = false }
|
quasi = { version = "0.32", default-features = false }
|
||||||
quasi_macros = { version = "0.11", optional = true }
|
quasi_macros = { version = "0.32", optional = true }
|
||||||
syntex = { version = "0.33", optional = true }
|
syntex = { version = "0.58", optional = true }
|
||||||
syntex_syntax = { version = "0.33", optional = true }
|
syntex_syntax = { version = "0.58", optional = true }
|
||||||
|
|||||||
@@ -25,13 +25,11 @@ mod inner {
|
|||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
let mut registry = syntex::Registry::new();
|
|
||||||
quasi_codegen::register(&mut registry);
|
|
||||||
|
|
||||||
let src = Path::new("src/lib.rs.in");
|
let src = Path::new("src/lib.rs.in");
|
||||||
let dst = Path::new(&out_dir).join("lib.rs");
|
let dst = Path::new(&out_dir).join("lib.rs");
|
||||||
|
|
||||||
registry.expand("", &src, &dst).unwrap();
|
quasi_codegen::expand(&src, &dst).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ pub fn expand_ipc_implementation(
|
|||||||
|
|
||||||
let builder = aster::AstBuilder::new().span(span);
|
let builder = aster::AstBuilder::new().span(span);
|
||||||
|
|
||||||
let interface_map = match implement_interface(cx, &builder, &item, push) {
|
let interface_map = match implement_interface(cx, &builder, &item, push, meta_item) {
|
||||||
Ok(interface_map) => interface_map,
|
Ok(interface_map) => interface_map,
|
||||||
Err(Error) => { return; },
|
Err(Error) => { return; },
|
||||||
};
|
};
|
||||||
@@ -99,9 +99,9 @@ fn push_invoke_signature_aster(
|
|||||||
let inputs = &named_signature.sig.decl.inputs;
|
let inputs = &named_signature.sig.decl.inputs;
|
||||||
let (input_type_name, input_arg_names, input_arg_tys) = if inputs.len() > 0 {
|
let (input_type_name, input_arg_names, input_arg_tys) = if inputs.len() > 0 {
|
||||||
let first_field_name = field_name(builder, &inputs[0]).name.as_str();
|
let first_field_name = field_name(builder, &inputs[0]).name.as_str();
|
||||||
if first_field_name == "self" && inputs.len() == 1 { (None, vec![], vec![]) }
|
if &*first_field_name == "self" && inputs.len() == 1 { (None, vec![], vec![]) }
|
||||||
else {
|
else {
|
||||||
let skip = if first_field_name == "self" { 2 } else { 1 };
|
let skip = if &*first_field_name == "self" { 2 } else { 1 };
|
||||||
let name_str = format!("{}_input", named_signature.ident.name.as_str());
|
let name_str = format!("{}_input", named_signature.ident.name.as_str());
|
||||||
|
|
||||||
let mut arg_names = Vec::new();
|
let mut arg_names = Vec::new();
|
||||||
@@ -181,6 +181,7 @@ fn implement_dispatch_arm_invoke_stmt(
|
|||||||
dispatch: &Dispatch,
|
dispatch: &Dispatch,
|
||||||
) -> ast::Stmt
|
) -> ast::Stmt
|
||||||
{
|
{
|
||||||
|
use ::syntax::tokenstream::TokenTree::Token;
|
||||||
let function_name = builder.id(dispatch.function_name.as_str());
|
let function_name = builder.id(dispatch.function_name.as_str());
|
||||||
|
|
||||||
let input_args_exprs = dispatch.input_arg_names.iter().enumerate().map(|(arg_index, arg_name)| {
|
let input_args_exprs = dispatch.input_arg_names.iter().enumerate().map(|(arg_index, arg_name)| {
|
||||||
@@ -193,56 +194,56 @@ fn implement_dispatch_arm_invoke_stmt(
|
|||||||
let ext_cx = &*cx;
|
let ext_cx = &*cx;
|
||||||
::quasi::parse_stmt_panic(&mut ::syntax::parse::new_parser_from_tts(
|
::quasi::parse_stmt_panic(&mut ::syntax::parse::new_parser_from_tts(
|
||||||
ext_cx.parse_sess(),
|
ext_cx.parse_sess(),
|
||||||
ext_cx.cfg(),
|
|
||||||
{
|
{
|
||||||
let _sp = ext_cx.call_site();
|
let _sp = ext_cx.call_site();
|
||||||
let mut tt = ::std::vec::Vec::new();
|
let mut tt = ::std::vec::Vec::new();
|
||||||
|
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
|
tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
|
||||||
|
|
||||||
if dispatch.return_type_ty.is_some() {
|
if dispatch.return_type_ty.is_some() {
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
|
tt.push(Token(_sp, ::syntax::parse::token::ModSep));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("ipc"))));
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("ipc"))));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
|
tt.push(Token(_sp, ::syntax::parse::token::ModSep));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("binary"))));
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("binary"))));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
|
tt.push(Token(_sp, ::syntax::parse::token::ModSep));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("serialize"))));
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("serialize"))));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
|
tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And)));
|
tt.push(Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And)));
|
||||||
}
|
}
|
||||||
|
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("self"))));
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("self"))));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot));
|
tt.push(Token(_sp, ::syntax::parse::token::Dot));
|
||||||
tt.extend(::quasi::ToTokens::to_tokens(&function_name, ext_cx).into_iter());
|
tt.extend(::quasi::ToTokens::to_tokens(&function_name, ext_cx).into_iter());
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
|
tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
|
||||||
|
|
||||||
for arg_expr in input_args_exprs {
|
for arg_expr in input_args_exprs {
|
||||||
tt.extend(::quasi::ToTokens::to_tokens(&arg_expr, ext_cx).into_iter());
|
tt.extend(::quasi::ToTokens::to_tokens(&arg_expr, ext_cx).into_iter());
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma));
|
tt.push(Token(_sp, ::syntax::parse::token::Comma));
|
||||||
}
|
}
|
||||||
|
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
|
tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
|
||||||
|
|
||||||
if dispatch.return_type_ty.is_some() {
|
if dispatch.return_type_ty.is_some() {
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
|
tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot));
|
tt.push(Token(_sp, ::syntax::parse::token::Dot));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("unwrap"))));
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("unwrap"))));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
|
tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
|
tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Semi));
|
tt.push(Token(_sp, ::syntax::parse::token::Semi));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("Vec"))));
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("Vec"))));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
|
tt.push(Token(_sp, ::syntax::parse::token::ModSep));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("new"))));
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("new"))));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
|
tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
|
tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
|
||||||
|
|
||||||
}
|
}
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace)));
|
tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace)));
|
||||||
|
|
||||||
tt
|
tt
|
||||||
})).unwrap()
|
}
|
||||||
|
)).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn implement_dispatch_arm_invoke(
|
fn implement_dispatch_arm_invoke(
|
||||||
@@ -344,6 +345,8 @@ fn implement_client_method_body(
|
|||||||
interface_map: &InterfaceMap,
|
interface_map: &InterfaceMap,
|
||||||
) -> P<ast::Expr>
|
) -> P<ast::Expr>
|
||||||
{
|
{
|
||||||
|
use ::syntax::tokenstream::TokenTree::Token;
|
||||||
|
|
||||||
let dispatch = &interface_map.dispatches[index as usize];
|
let dispatch = &interface_map.dispatches[index as usize];
|
||||||
let index_ident = builder.id(format!("{}", index + RESERVED_MESSAGE_IDS).as_str());
|
let index_ident = builder.id(format!("{}", index + RESERVED_MESSAGE_IDS).as_str());
|
||||||
|
|
||||||
@@ -391,26 +394,25 @@ fn implement_client_method_body(
|
|||||||
let ext_cx = &*cx;
|
let ext_cx = &*cx;
|
||||||
::quasi::parse_stmt_panic(&mut ::syntax::parse::new_parser_from_tts(
|
::quasi::parse_stmt_panic(&mut ::syntax::parse::new_parser_from_tts(
|
||||||
ext_cx.parse_sess(),
|
ext_cx.parse_sess(),
|
||||||
ext_cx.cfg(),
|
|
||||||
{
|
{
|
||||||
let _sp = ext_cx.call_site();
|
let _sp = ext_cx.call_site();
|
||||||
let mut tt = ::std::vec::Vec::new();
|
let mut tt = ::std::vec::Vec::new();
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("let"))));
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("let"))));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("payload"))));
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("payload"))));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Eq));
|
tt.push(Token(_sp, ::syntax::parse::token::Eq));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("Request"))));
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("Request"))));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
|
tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
|
||||||
|
|
||||||
for arg in dispatch.input_arg_names.iter() {
|
for arg in dispatch.input_arg_names.iter() {
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg.as_str()))));
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg.as_str()))));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Colon));
|
tt.push(Token(_sp, ::syntax::parse::token::Colon));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And)));
|
tt.push(Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And)));
|
||||||
|
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg.as_str()))));
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg.as_str()))));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma));
|
tt.push(Token(_sp, ::syntax::parse::token::Comma));
|
||||||
}
|
}
|
||||||
|
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace)));
|
tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace)));
|
||||||
tt
|
tt
|
||||||
}))
|
}))
|
||||||
});
|
});
|
||||||
@@ -465,6 +467,8 @@ fn implement_client_method(
|
|||||||
)
|
)
|
||||||
-> ast::ImplItem
|
-> ast::ImplItem
|
||||||
{
|
{
|
||||||
|
use ::syntax::tokenstream::TokenTree::Token;
|
||||||
|
|
||||||
let dispatch = &interface_map.dispatches[index as usize];
|
let dispatch = &interface_map.dispatches[index as usize];
|
||||||
let method_name = builder.id(dispatch.function_name.as_str());
|
let method_name = builder.id(dispatch.function_name.as_str());
|
||||||
let body = implement_client_method_body(cx, builder, index, interface_map);
|
let body = implement_client_method_body(cx, builder, index, interface_map);
|
||||||
@@ -476,36 +480,35 @@ fn implement_client_method(
|
|||||||
let signature = ::syntax::parse::parser::Parser::parse_impl_item(
|
let signature = ::syntax::parse::parser::Parser::parse_impl_item(
|
||||||
&mut ::syntax::parse::new_parser_from_tts(
|
&mut ::syntax::parse::new_parser_from_tts(
|
||||||
ext_cx.parse_sess(),
|
ext_cx.parse_sess(),
|
||||||
ext_cx.cfg(),
|
|
||||||
{
|
{
|
||||||
let _sp = ext_cx.call_site();
|
let _sp = ext_cx.call_site();
|
||||||
let mut tt = ::std::vec::Vec::new();
|
let mut tt = ::std::vec::Vec::new();
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("fn"))));
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("fn"))));
|
||||||
tt.extend(::quasi::ToTokens::to_tokens(&method_name, ext_cx).into_iter());
|
tt.extend(::quasi::ToTokens::to_tokens(&method_name, ext_cx).into_iter());
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
|
tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And)));
|
tt.push(Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And)));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("self"))));
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("self"))));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma));
|
tt.push(Token(_sp, ::syntax::parse::token::Comma));
|
||||||
|
|
||||||
for arg_idx in 0..dispatch.input_arg_names.len() {
|
for arg_idx in 0..dispatch.input_arg_names.len() {
|
||||||
let arg_name = dispatch.input_arg_names[arg_idx].as_str();
|
let arg_name = dispatch.input_arg_names[arg_idx].as_str();
|
||||||
let arg_ty = dispatch.input_arg_tys[arg_idx].clone();
|
let arg_ty = dispatch.input_arg_tys[arg_idx].clone();
|
||||||
|
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg_name))));
|
tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg_name))));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Colon));
|
tt.push(Token(_sp, ::syntax::parse::token::Colon));
|
||||||
tt.extend(::quasi::ToTokens::to_tokens(&arg_ty, ext_cx).into_iter());
|
tt.extend(::quasi::ToTokens::to_tokens(&arg_ty, ext_cx).into_iter());
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma));
|
tt.push(Token(_sp, ::syntax::parse::token::Comma));
|
||||||
}
|
}
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
|
tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
|
||||||
|
|
||||||
if let Some(ref return_ty) = dispatch.return_type_ty {
|
if let Some(ref return_ty) = dispatch.return_type_ty {
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::RArrow));
|
tt.push(Token(_sp, ::syntax::parse::token::RArrow));
|
||||||
tt.extend(::quasi::ToTokens::to_tokens(return_ty, ext_cx).into_iter());
|
tt.extend(::quasi::ToTokens::to_tokens(return_ty, ext_cx).into_iter());
|
||||||
}
|
}
|
||||||
|
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
|
tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
|
||||||
tt.extend(::quasi::ToTokens::to_tokens(&body, ext_cx).into_iter());
|
tt.extend(::quasi::ToTokens::to_tokens(&body, ext_cx).into_iter());
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace)));
|
tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace)));
|
||||||
|
|
||||||
tt
|
tt
|
||||||
}));
|
}));
|
||||||
@@ -526,7 +529,7 @@ fn client_generics(builder: &aster::AstBuilder, interface_map: &InterfaceMap) ->
|
|||||||
|
|
||||||
fn client_qualified_ident(cx: &ExtCtxt, builder: &aster::AstBuilder, interface_map: &InterfaceMap) -> P<Ty> {
|
fn client_qualified_ident(cx: &ExtCtxt, builder: &aster::AstBuilder, interface_map: &InterfaceMap) -> P<Ty> {
|
||||||
let generics = client_generics(builder, interface_map);
|
let generics = client_generics(builder, interface_map);
|
||||||
aster::ty::TyBuilder::new().path().segment(interface_map.ident_map.client_ident(cx, builder, &interface_map.original_item))
|
aster::ty::TyBuilder::new().path().segment(interface_map.ident_map.client_ident(cx, builder))
|
||||||
.with_generics(generics).build()
|
.with_generics(generics).build()
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
@@ -542,7 +545,7 @@ fn client_phantom_ident(builder: &aster::AstBuilder, interface_map: &InterfaceMa
|
|||||||
/// for say `Service` it generates `ServiceClient`
|
/// for say `Service` it generates `ServiceClient`
|
||||||
fn push_client_struct(cx: &ExtCtxt, builder: &aster::AstBuilder, interface_map: &InterfaceMap, push: &mut FnMut(Annotatable)) {
|
fn push_client_struct(cx: &ExtCtxt, builder: &aster::AstBuilder, interface_map: &InterfaceMap, push: &mut FnMut(Annotatable)) {
|
||||||
let generics = client_generics(builder, interface_map);
|
let generics = client_generics(builder, interface_map);
|
||||||
let client_short_ident = interface_map.ident_map.client_ident(cx, builder, &interface_map.original_item);
|
let client_short_ident = interface_map.ident_map.client_ident(cx, builder);
|
||||||
let phantom = client_phantom_ident(builder, interface_map);
|
let phantom = client_phantom_ident(builder, interface_map);
|
||||||
|
|
||||||
let client_struct_item = quote_item!(cx,
|
let client_struct_item = quote_item!(cx,
|
||||||
@@ -575,7 +578,7 @@ fn push_with_socket_client_implementation(
|
|||||||
let generics = client_generics(builder, interface_map);
|
let generics = client_generics(builder, interface_map);
|
||||||
let client_ident = client_qualified_ident(cx, builder, interface_map);
|
let client_ident = client_qualified_ident(cx, builder, interface_map);
|
||||||
let where_clause = &generics.where_clause;
|
let where_clause = &generics.where_clause;
|
||||||
let client_short_ident = interface_map.ident_map.client_ident(cx, builder, &interface_map.original_item);
|
let client_short_ident = interface_map.ident_map.client_ident(cx, builder);
|
||||||
|
|
||||||
let implement = quote_item!(cx,
|
let implement = quote_item!(cx,
|
||||||
impl $generics ::ipc::WithSocket<S> for $client_ident $where_clause {
|
impl $generics ::ipc::WithSocket<S> for $client_ident $where_clause {
|
||||||
@@ -717,33 +720,31 @@ fn get_str_from_lit(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Result<String,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_ipc_meta_items(attr: &ast::Attribute) -> Option<&[P<ast::MetaItem>]> {
|
fn client_ident_renamed(cx: &ExtCtxt, meta_item: &MetaItem) -> Option<String> {
|
||||||
match attr.node.value.node {
|
if let ast::MetaItemKind::List(ref list) = meta_item.node {
|
||||||
ast::MetaItemKind::List(ref name, ref items) if name == &"ipc" => {
|
for nested in list {
|
||||||
Some(items)
|
match nested.node {
|
||||||
}
|
ast::NestedMetaItemKind::MetaItem(ref meta_item) => {
|
||||||
_ => None
|
let is_client_ident = &*meta_item.name.as_str() == "client_ident";
|
||||||
}
|
match meta_item.node {
|
||||||
}
|
ast::MetaItemKind::NameValue(ref lit) if is_client_ident => {
|
||||||
|
if let Ok(s) = get_str_from_lit(cx, "client_ident", lit) {
|
||||||
fn client_ident_renamed(cx: &ExtCtxt, item: &ast::Item) -> Option<String> {
|
return Some(s);
|
||||||
for meta_items in item.attrs().iter().filter_map(get_ipc_meta_items) {
|
}
|
||||||
for meta_item in meta_items {
|
}
|
||||||
match meta_item.node {
|
_ => {
|
||||||
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"client_ident" => {
|
cx.span_err(
|
||||||
if let Ok(s) = get_str_from_lit(cx, name, lit) {
|
meta_item.span,
|
||||||
return Some(s);
|
&format!("unknown client_ident container attribute `{}`",
|
||||||
|
::syntax::print::pprust::meta_item_to_string(&meta_item)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
_ => {
|
_ => {},
|
||||||
cx.span_err(
|
|
||||||
meta_item.span,
|
|
||||||
&format!("unknown client_ident container attribute `{}`",
|
|
||||||
::syntax::print::pprust::meta_item_to_string(meta_item)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -759,6 +760,7 @@ struct InterfaceMap {
|
|||||||
|
|
||||||
struct IdentMap {
|
struct IdentMap {
|
||||||
original_path: ast::Path,
|
original_path: ast::Path,
|
||||||
|
meta_item: MetaItem,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IdentMap {
|
impl IdentMap {
|
||||||
@@ -766,8 +768,8 @@ impl IdentMap {
|
|||||||
builder.id(format!("{}", ::syntax::print::pprust::path_to_string(&self.original_path)))
|
builder.id(format!("{}", ::syntax::print::pprust::path_to_string(&self.original_path)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn client_ident(&self, cx: &ExtCtxt, builder: &aster::AstBuilder, item: &ast::Item) -> Ident {
|
fn client_ident(&self, cx: &ExtCtxt, builder: &aster::AstBuilder) -> Ident {
|
||||||
if let Some(new_name) = client_ident_renamed(cx, item) {
|
if let Some(new_name) = client_ident_renamed(cx, &self.meta_item) {
|
||||||
builder.id(new_name)
|
builder.id(new_name)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -776,12 +778,12 @@ impl IdentMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ty_ident_map(original_ty: &P<Ty>) -> IdentMap {
|
fn ty_ident_map(original_ty: &P<Ty>, meta_item: &MetaItem) -> IdentMap {
|
||||||
let original_path = match original_ty.node {
|
let original_path = match original_ty.node {
|
||||||
::syntax::ast::TyKind::Path(_, ref path) => path.clone(),
|
::syntax::ast::TyKind::Path(_, ref path) => path.clone(),
|
||||||
_ => { panic!("incompatible implementation"); }
|
_ => { panic!("incompatible implementation"); }
|
||||||
};
|
};
|
||||||
let ident_map = IdentMap { original_path: original_path };
|
let ident_map = IdentMap { original_path: original_path, meta_item: meta_item.clone() };
|
||||||
ident_map
|
ident_map
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -791,6 +793,7 @@ fn implement_interface(
|
|||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
item: &Item,
|
item: &Item,
|
||||||
push: &mut FnMut(Annotatable),
|
push: &mut FnMut(Annotatable),
|
||||||
|
meta_item: &MetaItem,
|
||||||
) -> Result<InterfaceMap, Error> {
|
) -> Result<InterfaceMap, Error> {
|
||||||
let (generics, impl_trait, original_ty, dispatch_table) = match item.node {
|
let (generics, impl_trait, original_ty, dispatch_table) = match item.node {
|
||||||
ast::ItemKind::Impl(_, _, ref generics, ref impl_trait, ref ty, ref impl_items) => {
|
ast::ItemKind::Impl(_, _, ref generics, ref impl_trait, ref ty, ref impl_items) => {
|
||||||
@@ -844,7 +847,7 @@ fn implement_interface(
|
|||||||
|
|
||||||
let (handshake_arm, handshake_arm_buf) = implement_handshake_arm(cx);
|
let (handshake_arm, handshake_arm_buf) = implement_handshake_arm(cx);
|
||||||
|
|
||||||
let ty = ty_ident_map(&original_ty).ident(builder);
|
let ty = ty_ident_map(&original_ty, meta_item).ident(builder);
|
||||||
let (interface_endpoint, host_generics) = match impl_trait {
|
let (interface_endpoint, host_generics) = match impl_trait {
|
||||||
Some(ref trait_) => (builder.id(::syntax::print::pprust::path_to_string(&trait_.path)), None),
|
Some(ref trait_) => (builder.id(::syntax::print::pprust::path_to_string(&trait_.path)), None),
|
||||||
None => (ty, Some(&impl_generics)),
|
None => (ty, Some(&impl_generics)),
|
||||||
@@ -884,7 +887,7 @@ fn implement_interface(
|
|||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
Ok(InterfaceMap {
|
Ok(InterfaceMap {
|
||||||
ident_map: ty_ident_map(&original_ty),
|
ident_map: ty_ident_map(&original_ty, meta_item),
|
||||||
original_item: item.clone(),
|
original_item: item.clone(),
|
||||||
item: ipc_item,
|
item: ipc_item,
|
||||||
dispatches: dispatch_table,
|
dispatches: dispatch_table,
|
||||||
|
|||||||
@@ -66,9 +66,11 @@ struct StripAttributeFolder<'a> {
|
|||||||
#[cfg(feature = "with-syntex")]
|
#[cfg(feature = "with-syntex")]
|
||||||
impl<'a> fold::Folder for StripAttributeFolder<'a> {
|
impl<'a> fold::Folder for StripAttributeFolder<'a> {
|
||||||
fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
|
fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
|
||||||
match attr.node.value.node {
|
let is_self = &*attr.value.name.as_str() == self.attr_title;
|
||||||
ast::MetaItemKind::List(ref n, _) if n == self.attr_title => { return None; }
|
|
||||||
ast::MetaItemKind::Word(ref n) if n == self.attr_title => { return None; }
|
match attr.value.node {
|
||||||
|
ast::MetaItemKind::List(_) if is_self => { return None; }
|
||||||
|
ast::MetaItemKind::Word if is_self => { return None; }
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ fn binary_expr(
|
|||||||
_ => {
|
_ => {
|
||||||
cx.span_bug(item.span,
|
cx.span_bug(item.span,
|
||||||
"expected ItemStruct or ItemEnum in #[derive(Binary)]");
|
"expected ItemStruct or ItemEnum in #[derive(Binary)]");
|
||||||
Err(Error)
|
Err(Error) as Result<BinaryExpressions, Error>
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,13 +184,17 @@ fn binary_expr_struct(
|
|||||||
let size_exprs: Vec<P<ast::Expr>> = fields.iter().enumerate().map(|(index, field)| {
|
let size_exprs: Vec<P<ast::Expr>> = fields.iter().enumerate().map(|(index, field)| {
|
||||||
let raw_ident = ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty));
|
let raw_ident = ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty));
|
||||||
let index_ident = builder.id(format!("__field{}", index));
|
let index_ident = builder.id(format!("__field{}", index));
|
||||||
|
let field_id = match field.ident {
|
||||||
|
Some(ident) => builder.id(ident),
|
||||||
|
None => builder.id(format!("{}", index)),
|
||||||
|
};
|
||||||
|
|
||||||
match raw_ident.as_ref() {
|
match raw_ident.as_ref() {
|
||||||
"u8" => {
|
"u8" => {
|
||||||
quote_expr!(cx, 1)
|
quote_expr!(cx, 1)
|
||||||
},
|
},
|
||||||
"[u8]" => {
|
"[u8]" => {
|
||||||
value_ident.and_then(|x| {
|
value_ident.and_then(|x| {
|
||||||
let field_id = builder.id(field.ident.unwrap());
|
|
||||||
Some(quote_expr!(cx, $x. $field_id .len()))
|
Some(quote_expr!(cx, $x. $field_id .len()))
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
@@ -207,7 +211,6 @@ fn binary_expr_struct(
|
|||||||
|
|
||||||
value_ident.and_then(|x|
|
value_ident.and_then(|x|
|
||||||
{
|
{
|
||||||
let field_id = builder.id(field.ident.unwrap());
|
|
||||||
Some(quote_expr!(cx,
|
Some(quote_expr!(cx,
|
||||||
match $field_type_ident_qualified::len_params() {
|
match $field_type_ident_qualified::len_params() {
|
||||||
0 => ::std::mem::size_of::<$field_type_ident>(),
|
0 => ::std::mem::size_of::<$field_type_ident>(),
|
||||||
@@ -232,12 +235,12 @@ fn binary_expr_struct(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut write_stmts = Vec::<ast::Stmt>::new();
|
let mut write_stmts = Vec::<ast::Stmt>::new();
|
||||||
write_stmts.push(quote_stmt!(cx, let mut offset = 0usize;).unwrap());
|
write_stmts.push(quote_stmt!(cx, let mut offset = 0usize;).expect("stmt1"));
|
||||||
|
|
||||||
let mut map_stmts = Vec::<ast::Stmt>::new();
|
let mut map_stmts = Vec::<ast::Stmt>::new();
|
||||||
let field_amount = builder.id(&format!("{}",fields.len()));
|
let field_amount = builder.id(&format!("{}",fields.len()));
|
||||||
map_stmts.push(quote_stmt!(cx, let mut map = vec![0usize; $field_amount];).unwrap());
|
map_stmts.push(quote_stmt!(cx, let mut map = vec![0usize; $field_amount];).expect("stmt2"));
|
||||||
map_stmts.push(quote_stmt!(cx, let mut total = 0usize;).unwrap());
|
map_stmts.push(quote_stmt!(cx, let mut total = 0usize;).expect("stmt3"));
|
||||||
|
|
||||||
let mut post_write_stmts = Vec::<ast::Stmt>::new();
|
let mut post_write_stmts = Vec::<ast::Stmt>::new();
|
||||||
|
|
||||||
@@ -248,9 +251,12 @@ fn binary_expr_struct(
|
|||||||
let field_type_ident_qualified = builder.id(
|
let field_type_ident_qualified = builder.id(
|
||||||
replace_qualified(&::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty))));
|
replace_qualified(&::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty))));
|
||||||
|
|
||||||
|
let field_id = match field.ident {
|
||||||
|
Some(ident) => builder.id(ident),
|
||||||
|
None => builder.id(format!("{}", index)),
|
||||||
|
};
|
||||||
let member_expr = match value_ident {
|
let member_expr = match value_ident {
|
||||||
Some(x) => {
|
Some(x) => {
|
||||||
let field_id = builder.id(field.ident.unwrap());
|
|
||||||
quote_expr!(cx, $x . $field_id)
|
quote_expr!(cx, $x . $field_id)
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
@@ -267,8 +273,8 @@ fn binary_expr_struct(
|
|||||||
|
|
||||||
match raw_ident.as_ref() {
|
match raw_ident.as_ref() {
|
||||||
"u8" => {
|
"u8" => {
|
||||||
write_stmts.push(quote_stmt!(cx, let next_line = offset + 1;).unwrap());
|
write_stmts.push(quote_stmt!(cx, let next_line = offset + 1;).expect("stmt4"));
|
||||||
write_stmts.push(quote_stmt!(cx, buffer[offset] = $member_expr; ).unwrap());
|
write_stmts.push(quote_stmt!(cx, buffer[offset] = $member_expr; ).expect("stm5"));
|
||||||
},
|
},
|
||||||
"[u8]" => {
|
"[u8]" => {
|
||||||
write_stmts.push(quote_stmt!(cx, let size = $member_expr .len();).unwrap());
|
write_stmts.push(quote_stmt!(cx, let size = $member_expr .len();).unwrap());
|
||||||
@@ -374,7 +380,7 @@ fn binary_expr_item_struct(
|
|||||||
cx.span_bug(span,
|
cx.span_bug(span,
|
||||||
&format!("#[derive(Binary)] Unsupported struct content, expected tuple/struct, found: {:?}",
|
&format!("#[derive(Binary)] Unsupported struct content, expected tuple/struct, found: {:?}",
|
||||||
variant_data));
|
variant_data));
|
||||||
Err(Error)
|
Err(Error) as Result<BinaryExpressions, Error>
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -431,13 +437,12 @@ fn fields_sequence(
|
|||||||
variant_ident: &ast::Ident,
|
variant_ident: &ast::Ident,
|
||||||
) -> ast::Expr {
|
) -> ast::Expr {
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use syntax::ast::TokenTree::Token;
|
use syntax::tokenstream::TokenTree::Token;
|
||||||
|
|
||||||
let named_members = fields.iter().any(|f| f.ident.is_some());
|
let named_members = fields.iter().any(|f| f.ident.is_some());
|
||||||
|
|
||||||
::quasi::parse_expr_panic(&mut ::syntax::parse::new_parser_from_tts(
|
::quasi::parse_expr_panic(&mut ::syntax::parse::new_parser_from_tts(
|
||||||
ext_cx.parse_sess(),
|
ext_cx.parse_sess(),
|
||||||
ext_cx.cfg(),
|
|
||||||
{
|
{
|
||||||
let _sp = ext_cx.call_site();
|
let _sp = ext_cx.call_site();
|
||||||
let mut tt = ::std::vec::Vec::new();
|
let mut tt = ::std::vec::Vec::new();
|
||||||
@@ -569,11 +574,10 @@ fn named_fields_sequence(
|
|||||||
fields: &[ast::StructField],
|
fields: &[ast::StructField],
|
||||||
) -> ast::Stmt {
|
) -> ast::Stmt {
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use syntax::ast::TokenTree::Token;
|
use syntax::tokenstream::TokenTree::Token;
|
||||||
|
|
||||||
::quasi::parse_stmt_panic(&mut ::syntax::parse::new_parser_from_tts(
|
::quasi::parse_stmt_panic(&mut ::syntax::parse::new_parser_from_tts(
|
||||||
ext_cx.parse_sess(),
|
ext_cx.parse_sess(),
|
||||||
ext_cx.cfg(),
|
|
||||||
{
|
{
|
||||||
let _sp = ext_cx.call_site();
|
let _sp = ext_cx.call_site();
|
||||||
let mut tt = ::std::vec::Vec::new();
|
let mut tt = ::std::vec::Vec::new();
|
||||||
@@ -590,7 +594,10 @@ fn named_fields_sequence(
|
|||||||
tt.push(Token(_sp, token::OpenDelim(token::Brace)));
|
tt.push(Token(_sp, token::OpenDelim(token::Brace)));
|
||||||
|
|
||||||
for (idx, field) in fields.iter().enumerate() {
|
for (idx, field) in fields.iter().enumerate() {
|
||||||
tt.push(Token(_sp, token::Ident(field.ident.clone().expect("function is called for named fields"))));
|
tt.push(Token(_sp, match field.ident {
|
||||||
|
Some(ident) => token::Ident(ident),
|
||||||
|
None => token::Ident(ext_cx.ident_of(&format!("{}", idx))),
|
||||||
|
}));
|
||||||
tt.push(Token(_sp, token::Colon));
|
tt.push(Token(_sp, token::Colon));
|
||||||
|
|
||||||
// special case for u8, it just takes byte form sequence
|
// special case for u8, it just takes byte form sequence
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ build = "build.rs"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ethcore-ipc = { path = "../rpc" }
|
ethcore-ipc = { path = "../rpc" }
|
||||||
nanomsg = { git = "https://github.com/ethcore/nanomsg.rs.git" }
|
nanomsg = { git = "https://github.com/paritytech/nanomsg.rs.git", branch = "parity-1.7" }
|
||||||
ethcore-ipc-nano = { path = "../nano" }
|
ethcore-ipc-nano = { path = "../nano" }
|
||||||
semver = "0.5"
|
semver = "0.5"
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
|
|||||||
@@ -8,6 +8,6 @@ license = "GPL-3.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ethcore-ipc = { path = "../rpc" }
|
ethcore-ipc = { path = "../rpc" }
|
||||||
nanomsg = { git = "https://github.com/ethcore/nanomsg.rs.git" }
|
nanomsg = { git = "https://github.com/paritytech/nanomsg.rs.git", branch = "parity-1.7" }
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
lazy_static = "0.2"
|
lazy_static = "0.2"
|
||||||
|
|||||||
@@ -8,6 +8,6 @@ license = "GPL-3.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ethcore-devtools = { path = "../../devtools" }
|
ethcore-devtools = { path = "../../devtools" }
|
||||||
nanomsg = { git = "https://github.com/ethcore/nanomsg.rs.git" }
|
nanomsg = { git = "https://github.com/paritytech/nanomsg.rs.git", branch = "parity-1.7" }
|
||||||
ethcore-util = { path = "../../util" }
|
ethcore-util = { path = "../../util" }
|
||||||
semver = "0.5"
|
semver = "0.5"
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ path = "run.rs"
|
|||||||
ethcore-ipc = { path = "../rpc" }
|
ethcore-ipc = { path = "../rpc" }
|
||||||
ethcore-devtools = { path = "../../devtools" }
|
ethcore-devtools = { path = "../../devtools" }
|
||||||
semver = "0.5"
|
semver = "0.5"
|
||||||
nanomsg = { git = "https://github.com/ethcore/nanomsg.rs.git" }
|
nanomsg = { git = "https://github.com/paritytech/nanomsg.rs.git", branch = "parity-1.7" }
|
||||||
ethcore-ipc-nano = { path = "../nano" }
|
ethcore-ipc-nano = { path = "../nano" }
|
||||||
ethcore-util = { path = "../../util" }
|
ethcore-util = { path = "../../util" }
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
ethcore = { path = "../ethcore" }
|
ethcore = { path = "../ethcore" }
|
||||||
ethcore-util = { path = "../util" }
|
ethcore-util = { path = "../util" }
|
||||||
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc.git" }
|
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc.git", branch = "parity-1.6" }
|
||||||
rlp = { path = "../util/rlp" }
|
rlp = { path = "../util/rlp" }
|
||||||
mime = "0.2"
|
mime = "0.2"
|
||||||
hyper = { default-features = false, git = "https://github.com/ethcore/hyper" }
|
hyper = { default-features = false, git = "https://github.com/ethcore/hyper" }
|
||||||
cid = "0.2.1"
|
cid = "0.2.2"
|
||||||
multihash = "0.5"
|
multihash = "0.6"
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ use-precompiled-js = ["parity-dapps-glue/use-precompiled-js"]
|
|||||||
with-syntex = ["parity-dapps-glue/with-syntex"]
|
with-syntex = ["parity-dapps-glue/with-syntex"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
parity-dapps-glue = "1.4"
|
parity-dapps-glue = "1.7"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
parity-dapps-glue = "1.4"
|
parity-dapps-glue = "1.7"
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
description = "Parity built-in dapps."
|
description = "Parity built-in dapps."
|
||||||
name = "parity-ui-dev"
|
name = "parity-ui-dev"
|
||||||
version = "1.4.0"
|
version = "1.7.0"
|
||||||
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"
|
||||||
@@ -11,8 +11,8 @@ default = ["with-syntex"]
|
|||||||
with-syntex = ["parity-dapps-glue/with-syntex"]
|
with-syntex = ["parity-dapps-glue/with-syntex"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
parity-dapps-glue = "1.4"
|
parity-dapps-glue = "1.7"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
parity-dapps-glue = "1.4"
|
parity-dapps-glue = "1.7"
|
||||||
|
|
||||||
|
|||||||
@@ -150,6 +150,7 @@
|
|||||||
"blockies": "0.0.2",
|
"blockies": "0.0.2",
|
||||||
"brace": "0.9.0",
|
"brace": "0.9.0",
|
||||||
"bytes": "2.4.0",
|
"bytes": "2.4.0",
|
||||||
|
"date-difference": "1.0.0",
|
||||||
"debounce": "1.0.0",
|
"debounce": "1.0.0",
|
||||||
"es6-error": "4.0.0",
|
"es6-error": "4.0.0",
|
||||||
"es6-promise": "4.0.5",
|
"es6-promise": "4.0.5",
|
||||||
@@ -198,7 +199,7 @@
|
|||||||
"redux-thunk": "2.1.0",
|
"redux-thunk": "2.1.0",
|
||||||
"rlp": "2.0.0",
|
"rlp": "2.0.0",
|
||||||
"scryptsy": "2.0.0",
|
"scryptsy": "2.0.0",
|
||||||
"solc": "ngotchac/solc-js",
|
"solc": "https://github.com/ngotchac/solc-js.git",
|
||||||
"store": "1.3.20",
|
"store": "1.3.20",
|
||||||
"u2f-api": "0.0.9",
|
"u2f-api": "0.0.9",
|
||||||
"u2f-api-polyfill": "0.4.3",
|
"u2f-api-polyfill": "0.4.3",
|
||||||
|
|||||||
@@ -37,7 +37,11 @@ Object.keys(rustMethods).forEach((group) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function printType (type) {
|
function printType (type, obj) {
|
||||||
|
if (!type) {
|
||||||
|
throw new Error(`Invalid type in ${JSON.stringify(obj)}`);
|
||||||
|
}
|
||||||
|
|
||||||
return type.print || `\`${type.name}\``;
|
return type.print || `\`${type.name}\``;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +49,7 @@ function formatDescription (obj, prefix = '', indent = '') {
|
|||||||
const optional = obj.optional ? '(optional) ' : '';
|
const optional = obj.optional ? '(optional) ' : '';
|
||||||
const defaults = obj.default ? `(default: \`${obj.default}\`) ` : '';
|
const defaults = obj.default ? `(default: \`${obj.default}\`) ` : '';
|
||||||
|
|
||||||
return `${indent}${prefix}${printType(obj.type)} - ${optional}${defaults}${obj.desc}`;
|
return `${indent}${prefix}${printType(obj.type, obj)} - ${optional}${defaults}${obj.desc}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatType (obj) {
|
function formatType (obj) {
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ set -e
|
|||||||
UTCDATE=`date -u "+%Y%m%d-%H%M%S"`
|
UTCDATE=`date -u "+%Y%m%d-%H%M%S"`
|
||||||
PACKAGES=( "parity" "etherscan" "shapeshift" "jsonrpc" )
|
PACKAGES=( "parity" "etherscan" "shapeshift" "jsonrpc" )
|
||||||
BRANCH=$CI_BUILD_REF_NAME
|
BRANCH=$CI_BUILD_REF_NAME
|
||||||
GIT_JS_PRECOMPILED="https://${GITHUB_JS_PRECOMPILED}:@github.com/ethcore/js-precompiled.git"
|
GIT_JS_PRECOMPILED="https://${GITHUB_JS_PRECOMPILED}:@github.com/paritytech/js-precompiled.git"
|
||||||
GIT_PARITY="https://${GITHUB_JS_PRECOMPILED}:@github.com/ethcore/parity.git"
|
GIT_PARITY="https://${GITHUB_JS_PRECOMPILED}:@github.com/paritytech/parity.git"
|
||||||
|
|
||||||
# setup the git user defaults for the current repo
|
# setup the git user defaults for the current repo
|
||||||
function setup_git_user {
|
function setup_git_user {
|
||||||
|
|||||||
@@ -107,34 +107,26 @@ export default class Contract {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
deploy (options, values, statecb) {
|
deploy (options, values, statecb = () => {}) {
|
||||||
const setState = (state) => {
|
statecb(null, { state: 'estimateGas' });
|
||||||
if (!statecb) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return statecb(null, state);
|
|
||||||
};
|
|
||||||
|
|
||||||
setState({ state: 'estimateGas' });
|
|
||||||
|
|
||||||
return this
|
return this
|
||||||
.deployEstimateGas(options, values)
|
.deployEstimateGas(options, values)
|
||||||
.then(([gasEst, gas]) => {
|
.then(([gasEst, gas]) => {
|
||||||
options.gas = gas.toFixed(0);
|
options.gas = gas.toFixed(0);
|
||||||
|
|
||||||
setState({ state: 'postTransaction', gas });
|
statecb(null, { state: 'postTransaction', gas });
|
||||||
|
|
||||||
const _options = this._encodeOptions(this.constructors[0], options, values);
|
const encodedOptions = this._encodeOptions(this.constructors[0], options, values);
|
||||||
|
|
||||||
return this._api.parity
|
return this._api.parity
|
||||||
.postTransaction(_options)
|
.postTransaction(encodedOptions)
|
||||||
.then((requestId) => {
|
.then((requestId) => {
|
||||||
setState({ state: 'checkRequest', requestId });
|
statecb(null, { state: 'checkRequest', requestId });
|
||||||
return this._pollCheckRequest(requestId);
|
return this._pollCheckRequest(requestId);
|
||||||
})
|
})
|
||||||
.then((txhash) => {
|
.then((txhash) => {
|
||||||
setState({ state: 'getTransactionReceipt', txhash });
|
statecb(null, { state: 'getTransactionReceipt', txhash });
|
||||||
return this._pollTransactionReceipt(txhash, gas);
|
return this._pollTransactionReceipt(txhash, gas);
|
||||||
})
|
})
|
||||||
.then((receipt) => {
|
.then((receipt) => {
|
||||||
@@ -142,23 +134,23 @@ export default class Contract {
|
|||||||
throw new Error(`Contract not deployed, gasUsed == ${gas.toFixed(0)}`);
|
throw new Error(`Contract not deployed, gasUsed == ${gas.toFixed(0)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
setState({ state: 'hasReceipt', receipt });
|
statecb(null, { state: 'hasReceipt', receipt });
|
||||||
this._receipt = receipt;
|
this._receipt = receipt;
|
||||||
this._address = receipt.contractAddress;
|
this._address = receipt.contractAddress;
|
||||||
return this._address;
|
return this._address;
|
||||||
});
|
})
|
||||||
})
|
.then((address) => {
|
||||||
.then((address) => {
|
statecb(null, { state: 'getCode' });
|
||||||
setState({ state: 'getCode' });
|
return this._api.eth.getCode(this._address);
|
||||||
return this._api.eth.getCode(this._address);
|
})
|
||||||
})
|
.then((code) => {
|
||||||
.then((code) => {
|
if (code === '0x') {
|
||||||
if (code === '0x') {
|
throw new Error('Contract not deployed, getCode returned 0x');
|
||||||
throw new Error('Contract not deployed, getCode returned 0x');
|
}
|
||||||
}
|
|
||||||
|
|
||||||
setState({ state: 'completed' });
|
statecb(null, { state: 'completed' });
|
||||||
return this._address;
|
return this._address;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -143,8 +143,15 @@ export function inOptions (options) {
|
|||||||
if (options) {
|
if (options) {
|
||||||
Object.keys(options).forEach((key) => {
|
Object.keys(options).forEach((key) => {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'from':
|
|
||||||
case 'to':
|
case 'to':
|
||||||
|
// Don't encode the `to` option if it's empty
|
||||||
|
// (eg. contract deployments)
|
||||||
|
if (options[key]) {
|
||||||
|
options[key] = inAddress(options[key]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'from':
|
||||||
options[key] = inAddress(options[key]);
|
options[key] = inAddress(options[key]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -204,3 +211,36 @@ export function inTraceType (whatTrace) {
|
|||||||
|
|
||||||
return whatTrace;
|
return whatTrace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function inDeriveType (derive) {
|
||||||
|
return derive && derive.type === 'hard' ? 'hard' : 'soft';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function inDeriveHash (derive) {
|
||||||
|
const hash = derive && derive.hash ? derive.hash : derive;
|
||||||
|
const type = inDeriveType(derive);
|
||||||
|
|
||||||
|
return {
|
||||||
|
hash: inHex(hash),
|
||||||
|
type
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function inDeriveIndex (derive) {
|
||||||
|
if (!derive) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isArray(derive)) {
|
||||||
|
derive = [derive];
|
||||||
|
}
|
||||||
|
|
||||||
|
return derive.map(item => {
|
||||||
|
const index = inNumber10(item && item.index ? item.index : item);
|
||||||
|
|
||||||
|
return {
|
||||||
|
index,
|
||||||
|
type: inDeriveType(item)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,7 +16,11 @@
|
|||||||
|
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
|
|
||||||
import { inAddress, inBlockNumber, inData, inFilter, inHex, inNumber10, inNumber16, inOptions, inTraceType } from './input';
|
import {
|
||||||
|
inAddress, inBlockNumber, inData, inFilter, inHex,
|
||||||
|
inNumber10, inNumber16, inOptions, inTraceType,
|
||||||
|
inDeriveHash, inDeriveIndex
|
||||||
|
} from './input';
|
||||||
import { isAddress } from '../../../test/types';
|
import { isAddress } from '../../../test/types';
|
||||||
|
|
||||||
describe('api/format/input', () => {
|
describe('api/format/input', () => {
|
||||||
@@ -208,7 +212,14 @@ describe('api/format/input', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
['gas', 'gasPrice', 'value', 'minBlock', 'nonce'].forEach((input) => {
|
it('does not encode an empty `to` value', () => {
|
||||||
|
const options = { to: '' };
|
||||||
|
const formatted = inOptions(options);
|
||||||
|
|
||||||
|
expect(formatted.to).to.equal('');
|
||||||
|
});
|
||||||
|
|
||||||
|
['gas', 'gasPrice', 'value', 'nonce'].forEach((input) => {
|
||||||
it(`formats ${input} number as hexnumber`, () => {
|
it(`formats ${input} number as hexnumber`, () => {
|
||||||
const block = {};
|
const block = {};
|
||||||
|
|
||||||
@@ -219,8 +230,8 @@ describe('api/format/input', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('passes minBlock as null when specified as such', () => {
|
it('passes condition as null when specified as such', () => {
|
||||||
expect(inOptions({ minBlock: null })).to.deep.equal({ minBlock: null });
|
expect(inOptions({ condition: null })).to.deep.equal({ condition: null });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('ignores and passes through unknown keys', () => {
|
it('ignores and passes through unknown keys', () => {
|
||||||
@@ -265,4 +276,66 @@ describe('api/format/input', () => {
|
|||||||
expect(inTraceType(type)).to.deep.equal([type]);
|
expect(inTraceType(type)).to.deep.equal([type]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('inDeriveHash', () => {
|
||||||
|
it('returns derive hash', () => {
|
||||||
|
expect(inDeriveHash(1)).to.deep.equal({
|
||||||
|
hash: '0x1',
|
||||||
|
type: 'soft'
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(inDeriveHash(null)).to.deep.equal({
|
||||||
|
hash: '0x',
|
||||||
|
type: 'soft'
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(inDeriveHash({
|
||||||
|
hash: 5
|
||||||
|
})).to.deep.equal({
|
||||||
|
hash: '0x5',
|
||||||
|
type: 'soft'
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(inDeriveHash({
|
||||||
|
hash: 5,
|
||||||
|
type: 'hard'
|
||||||
|
})).to.deep.equal({
|
||||||
|
hash: '0x5',
|
||||||
|
type: 'hard'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('inDeriveIndex', () => {
|
||||||
|
it('returns derive hash', () => {
|
||||||
|
expect(inDeriveIndex(null)).to.deep.equal([]);
|
||||||
|
expect(inDeriveIndex([])).to.deep.equal([]);
|
||||||
|
|
||||||
|
expect(inDeriveIndex([1])).to.deep.equal([{
|
||||||
|
index: 1,
|
||||||
|
type: 'soft'
|
||||||
|
}]);
|
||||||
|
|
||||||
|
expect(inDeriveIndex({
|
||||||
|
index: 1
|
||||||
|
})).to.deep.equal([{
|
||||||
|
index: 1,
|
||||||
|
type: 'soft'
|
||||||
|
}]);
|
||||||
|
|
||||||
|
expect(inDeriveIndex([{
|
||||||
|
index: 1,
|
||||||
|
type: 'hard'
|
||||||
|
}, 5])).to.deep.equal([
|
||||||
|
{
|
||||||
|
index: 1,
|
||||||
|
type: 'hard'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
index: 5,
|
||||||
|
type: 'soft'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -280,12 +280,6 @@ export function outTransaction (tx) {
|
|||||||
tx[key] = outTransactionCondition(tx[key]);
|
tx[key] = outTransactionCondition(tx[key]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'minBlock':
|
|
||||||
tx[key] = tx[key]
|
|
||||||
? outNumber(tx[key])
|
|
||||||
: null;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'creates':
|
case 'creates':
|
||||||
case 'from':
|
case 'from':
|
||||||
case 'to':
|
case 'to':
|
||||||
|
|||||||
@@ -384,7 +384,7 @@ describe('api/format/output', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
['blockNumber', 'gasPrice', 'gas', 'minBlock', 'nonce', 'transactionIndex', 'value'].forEach((input) => {
|
['blockNumber', 'gasPrice', 'gas', 'nonce', 'transactionIndex', 'value'].forEach((input) => {
|
||||||
it(`formats ${input} number as hexnumber`, () => {
|
it(`formats ${input} number as hexnumber`, () => {
|
||||||
const block = {};
|
const block = {};
|
||||||
|
|
||||||
@@ -396,8 +396,8 @@ describe('api/format/output', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('passes minBlock as null when null', () => {
|
it('passes condition as null when null', () => {
|
||||||
expect(outTransaction({ minBlock: null })).to.deep.equal({ minBlock: null });
|
expect(outTransaction({ condition: null })).to.deep.equal({ condition: null });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('ignores and passes through unknown keys', () => {
|
it('ignores and passes through unknown keys', () => {
|
||||||
|
|||||||
@@ -14,7 +14,9 @@
|
|||||||
// 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, inBlockNumber } from '../../format/input';
|
import {
|
||||||
|
inAddress, inAddresses, inData, inHex, inNumber16, inOptions, inBlockNumber, inDeriveHash, inDeriveIndex
|
||||||
|
} from '../../format/input';
|
||||||
import { outAccountInfo, outAddress, outAddresses, outChainStatus, outHistogram, outHwAccountInfo, outNumber, outPeers, outRecentDapps, outTransaction, outVaultMeta } from '../../format/output';
|
import { outAccountInfo, outAddress, outAddresses, outChainStatus, outHistogram, outHwAccountInfo, outNumber, outPeers, outRecentDapps, outTransaction, outVaultMeta } from '../../format/output';
|
||||||
|
|
||||||
export default class Parity {
|
export default class Parity {
|
||||||
@@ -117,6 +119,18 @@ export default class Parity {
|
|||||||
.execute('parity_devLogsLevels');
|
.execute('parity_devLogsLevels');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deriveAddressHash (address, password, hash, shouldSave) {
|
||||||
|
return this._transport
|
||||||
|
.execute('parity_deriveAddressHash', inAddress(address), password, inDeriveHash(hash), !!shouldSave)
|
||||||
|
.then(outAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
deriveAddressIndex (address, password, index, shouldSave) {
|
||||||
|
return this._transport
|
||||||
|
.execute('parity_deriveAddressIndex', inAddress(address), password, inDeriveIndex(index), !!shouldSave)
|
||||||
|
.then(outAddress);
|
||||||
|
}
|
||||||
|
|
||||||
dropNonReservedPeers () {
|
dropNonReservedPeers () {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('parity_dropNonReservedPeers');
|
.execute('parity_dropNonReservedPeers');
|
||||||
@@ -137,6 +151,11 @@ export default class Parity {
|
|||||||
.execute('parity_executeUpgrade');
|
.execute('parity_executeUpgrade');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exportAccount (address, password) {
|
||||||
|
return this._transport
|
||||||
|
.execute('parity_exportAccount', inAddress(address), password);
|
||||||
|
}
|
||||||
|
|
||||||
extraData () {
|
extraData () {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('parity_extraData');
|
.execute('parity_extraData');
|
||||||
@@ -389,6 +408,12 @@ export default class Parity {
|
|||||||
.execute('parity_removeReservedPeer', encode);
|
.execute('parity_removeReservedPeer', encode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
removeTransaction (hash) {
|
||||||
|
return this._transport
|
||||||
|
.execute('parity_removeTransaction', inHex(hash))
|
||||||
|
.then(outTransaction);
|
||||||
|
}
|
||||||
|
|
||||||
rpcSettings () {
|
rpcSettings () {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('parity_rpcSettings');
|
.execute('parity_rpcSettings');
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export default class Personal {
|
|||||||
|
|
||||||
// FIXME: Because of the different API instances, the "wait for valid changes" approach
|
// 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
|
// 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
|
// same way we do in ../eth (ala eth_blockNumber) and update. This should be moved
|
||||||
// to pub-sub as it becomes available
|
// to pub-sub as it becomes available
|
||||||
_defaultAccount = (timerDisabled = false) => {
|
_defaultAccount = (timerDisabled = false) => {
|
||||||
const nextTimeout = (timeout = 1000) => {
|
const nextTimeout = (timeout = 1000) => {
|
||||||
|
|||||||
466
js/src/contracts/abi/old-wallet.json
Normal file
466
js/src/contracts/abi/old-wallet.json
Normal file
@@ -0,0 +1,466 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_owner",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "removeOwner",
|
||||||
|
"outputs": [],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_addr",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "isOwner",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [],
|
||||||
|
"name": "m_numOwners",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [],
|
||||||
|
"name": "m_lastDay",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [],
|
||||||
|
"name": "resetSpentToday",
|
||||||
|
"outputs": [],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [],
|
||||||
|
"name": "m_spentToday",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_owner",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "addOwner",
|
||||||
|
"outputs": [],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [],
|
||||||
|
"name": "m_required",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_h",
|
||||||
|
"type": "bytes32"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "confirm",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_newLimit",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "setDailyLimit",
|
||||||
|
"outputs": [],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_to",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "_value",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "_data",
|
||||||
|
"type": "bytes"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "execute",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "_r",
|
||||||
|
"type": "bytes32"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_operation",
|
||||||
|
"type": "bytes32"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "revoke",
|
||||||
|
"outputs": [],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_newRequired",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "changeRequirement",
|
||||||
|
"outputs": [],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_operation",
|
||||||
|
"type": "bytes32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "_owner",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "hasConfirmed",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "ownerIndex",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "getOwner",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_to",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "kill",
|
||||||
|
"outputs": [],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_from",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "_to",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "changeOwner",
|
||||||
|
"outputs": [],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [],
|
||||||
|
"name": "m_dailyLimit",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_owners",
|
||||||
|
"type": "address[]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "_required",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "_daylimit",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "constructor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "owner",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "operation",
|
||||||
|
"type": "bytes32"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Confirmation",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "owner",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "operation",
|
||||||
|
"type": "bytes32"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Revoke",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "oldOwner",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "newOwner",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "OwnerChanged",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "newOwner",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "OwnerAdded",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "oldOwner",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "OwnerRemoved",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "newRequirement",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "RequirementChanged",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "_from",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "value",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Deposit",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "owner",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "value",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "to",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "data",
|
||||||
|
"type": "bytes"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "SingleTransact",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "owner",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "operation",
|
||||||
|
"type": "bytes32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "value",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "to",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "data",
|
||||||
|
"type": "bytes"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "MultiTransact",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "operation",
|
||||||
|
"type": "bytes32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "initiator",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "value",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "to",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "data",
|
||||||
|
"type": "bytes"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "ConfirmationNeeded",
|
||||||
|
"type": "event"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -1 +1,476 @@
|
|||||||
[{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"removeOwner","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_addr","type":"address"}],"name":"isOwner","outputs":[{"name":"","type":"bool"}],"type":"function"},{"constant":true,"inputs":[],"name":"m_numOwners","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"m_lastDay","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[],"name":"resetSpentToday","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"m_spentToday","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"addOwner","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"m_required","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"_h","type":"bytes32"}],"name":"confirm","outputs":[{"name":"","type":"bool"}],"type":"function"},{"constant":false,"inputs":[{"name":"_newLimit","type":"uint256"}],"name":"setDailyLimit","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"},{"name":"_data","type":"bytes"}],"name":"execute","outputs":[{"name":"_r","type":"bytes32"}],"type":"function"},{"constant":false,"inputs":[{"name":"_operation","type":"bytes32"}],"name":"revoke","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_newRequired","type":"uint256"}],"name":"changeRequirement","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"_operation","type":"bytes32"},{"name":"_owner","type":"address"}],"name":"hasConfirmed","outputs":[{"name":"","type":"bool"}],"type":"function"},{"constant":true,"inputs":[{"name":"ownerIndex","type":"uint256"}],"name":"getOwner","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"}],"name":"kill","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"}],"name":"changeOwner","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"m_dailyLimit","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"inputs":[{"name":"_owners","type":"address[]"},{"name":"_required","type":"uint256"},{"name":"_daylimit","type":"uint256"}],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"operation","type":"bytes32"}],"name":"Confirmation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"operation","type":"bytes32"}],"name":"Revoke","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"oldOwner","type":"address"},{"indexed":false,"name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newOwner","type":"address"}],"name":"OwnerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"oldOwner","type":"address"}],"name":"OwnerRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newRequirement","type":"uint256"}],"name":"RequirementChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_from","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"value","type":"uint256"},{"indexed":false,"name":"to","type":"address"},{"indexed":false,"name":"data","type":"bytes"}],"name":"SingleTransact","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"operation","type":"bytes32"},{"indexed":false,"name":"value","type":"uint256"},{"indexed":false,"name":"to","type":"address"},{"indexed":false,"name":"data","type":"bytes"}],"name":"MultiTransact","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"operation","type":"bytes32"},{"indexed":false,"name":"initiator","type":"address"},{"indexed":false,"name":"value","type":"uint256"},{"indexed":false,"name":"to","type":"address"},{"indexed":false,"name":"data","type":"bytes"}],"name":"ConfirmationNeeded","type":"event"}]
|
[
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_owner",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "removeOwner",
|
||||||
|
"outputs": [],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_addr",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "isOwner",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [],
|
||||||
|
"name": "m_numOwners",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [],
|
||||||
|
"name": "m_lastDay",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [],
|
||||||
|
"name": "resetSpentToday",
|
||||||
|
"outputs": [],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [],
|
||||||
|
"name": "m_spentToday",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_owner",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "addOwner",
|
||||||
|
"outputs": [],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [],
|
||||||
|
"name": "m_required",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_h",
|
||||||
|
"type": "bytes32"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "confirm",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_newLimit",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "setDailyLimit",
|
||||||
|
"outputs": [],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_to",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "_value",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "_data",
|
||||||
|
"type": "bytes"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "execute",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "_r",
|
||||||
|
"type": "bytes32"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_operation",
|
||||||
|
"type": "bytes32"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "revoke",
|
||||||
|
"outputs": [],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_newRequired",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "changeRequirement",
|
||||||
|
"outputs": [],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_operation",
|
||||||
|
"type": "bytes32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "_owner",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "hasConfirmed",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "ownerIndex",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "getOwner",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_to",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "kill",
|
||||||
|
"outputs": [],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_from",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "_to",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "changeOwner",
|
||||||
|
"outputs": [],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [],
|
||||||
|
"name": "m_dailyLimit",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_owners",
|
||||||
|
"type": "address[]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "_required",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "_daylimit",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "constructor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "owner",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "operation",
|
||||||
|
"type": "bytes32"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Confirmation",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "owner",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "operation",
|
||||||
|
"type": "bytes32"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Revoke",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "oldOwner",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "newOwner",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "OwnerChanged",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "newOwner",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "OwnerAdded",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "oldOwner",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "OwnerRemoved",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "newRequirement",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "RequirementChanged",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "_from",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "value",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Deposit",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "owner",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "value",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "to",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "data",
|
||||||
|
"type": "bytes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "created",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "SingleTransact",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "owner",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "operation",
|
||||||
|
"type": "bytes32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "value",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "to",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "data",
|
||||||
|
"type": "bytes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "created",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "MultiTransact",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "operation",
|
||||||
|
"type": "bytes32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "initiator",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "value",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "to",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "data",
|
||||||
|
"type": "bytes"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "ConfirmationNeeded",
|
||||||
|
"type": "event"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -16,7 +16,14 @@
|
|||||||
|
|
||||||
import * as abis from './abi';
|
import * as abis from './abi';
|
||||||
|
|
||||||
|
const REGISTRY_V1_HASHES = [
|
||||||
|
'0x34f7c51bbb1b1902fbdabfdf04811100f5c9f998f26dd535d2f6f977492c748e', // ropsten
|
||||||
|
'0x64c3ee34851517a9faecd995c102b339f03e564ad6772dc43a26f993238b20ec' // homestead
|
||||||
|
];
|
||||||
|
|
||||||
export default class Registry {
|
export default class Registry {
|
||||||
|
_registryContract = null;
|
||||||
|
|
||||||
constructor (api) {
|
constructor (api) {
|
||||||
this._api = api;
|
this._api = api;
|
||||||
|
|
||||||
@@ -43,11 +50,10 @@ export default class Registry {
|
|||||||
|
|
||||||
this._fetching = true;
|
this._fetching = true;
|
||||||
|
|
||||||
return this._api.parity
|
return this.fetchContract()
|
||||||
.registryAddress()
|
.then((contract) => {
|
||||||
.then((address) => {
|
|
||||||
this._fetching = false;
|
this._fetching = false;
|
||||||
this._instance = this._api.newContract(abis.registry, address).instance;
|
this._instance = contract.instance;
|
||||||
|
|
||||||
this._queue.forEach((queued) => {
|
this._queue.forEach((queued) => {
|
||||||
queued.resolve(this._instance);
|
queued.resolve(this._instance);
|
||||||
@@ -89,6 +95,47 @@ export default class Registry {
|
|||||||
.then((contract) => contract.instance);
|
.then((contract) => contract.instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fetchContract () {
|
||||||
|
if (this._registryContract) {
|
||||||
|
return Promise.resolve(this._registryContract);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._api.parity
|
||||||
|
.registryAddress()
|
||||||
|
.then((address) => Promise.all([ address, this._api.eth.getCode(address) ]))
|
||||||
|
.then(([ address, code ]) => {
|
||||||
|
const codeHash = this._api.util.sha3(code);
|
||||||
|
const version = REGISTRY_V1_HASHES.includes(codeHash)
|
||||||
|
? 1
|
||||||
|
: 2;
|
||||||
|
const abi = version === 1
|
||||||
|
? abis.registry
|
||||||
|
: abis.registry2;
|
||||||
|
const contract = this._api.newContract(abi, address);
|
||||||
|
|
||||||
|
// Add support for previous `set` and `get` methods
|
||||||
|
if (!contract.instance.get && contract.instance.getData) {
|
||||||
|
contract.instance.get = contract.instance.getData;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contract.instance.get && !contract.instance.getData) {
|
||||||
|
contract.instance.getData = contract.instance.get;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!contract.instance.set && contract.instance.setData) {
|
||||||
|
contract.instance.set = contract.instance.setData;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contract.instance.set && !contract.instance.setData) {
|
||||||
|
contract.instance.setData = contract.instance.set;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`registry at ${address}, code ${codeHash}, version ${version}`);
|
||||||
|
this._registryContract = contract;
|
||||||
|
return this._registryContract;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
_createGetParams (_name, key) {
|
_createGetParams (_name, key) {
|
||||||
const name = _name.toLowerCase();
|
const name = _name.toLowerCase();
|
||||||
const sha3 = this._api.util.sha3.text(name);
|
const sha3 = this._api.util.sha3.text(name);
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ function create () {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
api = {
|
api = {
|
||||||
|
eth: {
|
||||||
|
getCode: sinon.stub().resolves(0)
|
||||||
|
},
|
||||||
parity: {
|
parity: {
|
||||||
registryAddress: sinon.stub().resolves('testRegistryAddress')
|
registryAddress: sinon.stub().resolves('testRegistryAddress')
|
||||||
},
|
},
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user