Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
804ddfe31e | ||
|
|
3bfb2fa1aa | ||
|
|
9d697c5d0a | ||
|
|
6a29fea23c | ||
|
|
deecf8927c | ||
|
|
acef56b1ea | ||
|
|
14d29798e3 | ||
|
|
5fc06c0e24 | ||
|
|
62be23eef5 | ||
|
|
57b8efb86a | ||
|
|
8f841767a4 | ||
|
|
d30c035440 | ||
|
|
89dc08a5cd | ||
|
|
fa0e2a7449 | ||
|
|
1de095f3bd | ||
|
|
b60511e3d2 | ||
|
|
af70a681d5 | ||
|
|
7adfb82076 | ||
|
|
d504ce64e8 | ||
|
|
0feb0bb6e7 | ||
|
|
3b5a8d5d69 | ||
|
|
aca9f13d45 | ||
|
|
e09bef98fb | ||
|
|
ceb590a360 | ||
|
|
75c0db2b15 | ||
|
|
70b42345c5 | ||
|
|
a42d780d02 | ||
|
|
582fa8ce45 | ||
|
|
73be0fb096 | ||
|
|
627d1a4971 | ||
|
|
a7807106f5 | ||
|
|
33b39f0725 | ||
|
|
53ec1141cf | ||
|
|
145229d46d | ||
|
|
568dc33a02 | ||
|
|
cf10450108 | ||
|
|
fe779686ca | ||
|
|
58c1dbe322 | ||
|
|
14b578832d | ||
|
|
e961398393 | ||
|
|
0fad2a6d8c | ||
|
|
f3bcada7b9 | ||
|
|
b814f1ccbf | ||
|
|
cad91df2b8 | ||
|
|
50a58e1ae8 | ||
|
|
1e36fc5d0f | ||
|
|
fa6a0a6b60 | ||
|
|
a8fc42d282 | ||
|
|
c6685a7f57 | ||
|
|
736a8c40f0 | ||
|
|
5f74f8c265 | ||
|
|
97ed569588 | ||
|
|
6766ef988d | ||
|
|
8a87cfb893 | ||
|
|
54aebdcb45 | ||
|
|
86a6145d76 | ||
|
|
718020b64b | ||
|
|
8c36a56365 | ||
|
|
7bccaa5c15 | ||
|
|
98ec46fff6 | ||
|
|
8dc584ece9 | ||
|
|
63d154dad3 | ||
|
|
0030bb4f1d |
@@ -9,7 +9,7 @@ trim_trailing_whitespace=true
|
||||
max_line_length=120
|
||||
insert_final_newline=true
|
||||
|
||||
[.travis.yml]
|
||||
[*.{yml,sh}]
|
||||
indent_style=space
|
||||
indent_size=2
|
||||
tab_width=8
|
||||
|
||||
558
.gitlab-ci.yml
@@ -4,13 +4,17 @@ stages:
|
||||
- push-release
|
||||
- build
|
||||
variables:
|
||||
SIMPLECOV: "true"
|
||||
RUST_BACKTRACE: "1"
|
||||
RUSTFLAGS: ""
|
||||
CARGOFLAGS: ""
|
||||
CI_SERVER_NAME: "GitLab CI"
|
||||
LIBSSL: "libssl1.0.0 (>=1.0.0)"
|
||||
CARGO_HOME: $CI_PROJECT_DIR/cargo
|
||||
cache:
|
||||
key: "$CI_BUILD_STAGE/$CI_BUILD_REF_NAME"
|
||||
key: "$CI_BUILD_STAGE-$CI_BUILD_REF_NAME"
|
||||
paths:
|
||||
- target/
|
||||
- cargo/
|
||||
untracked: true
|
||||
linux-stable:
|
||||
stage: build
|
||||
@@ -22,77 +26,14 @@ linux-stable:
|
||||
- triggers
|
||||
script:
|
||||
- rustup default stable
|
||||
- cargo build -j $(nproc) --release --features final $CARGOFLAGS
|
||||
- cargo build -j $(nproc) --release -p evmbin
|
||||
- cargo build -j $(nproc) --release -p ethstore-cli
|
||||
- cargo build -j $(nproc) --release -p ethkey-cli
|
||||
- strip target/release/parity
|
||||
- strip target/release/parity-evm
|
||||
- strip target/release/ethstore
|
||||
- strip target/release/ethkey
|
||||
- export SHA3=$(target/release/parity tools hash target/release/parity)
|
||||
- md5sum target/release/parity > parity.md5
|
||||
- sh scripts/deb-build.sh amd64
|
||||
- cp target/release/parity deb/usr/bin/parity
|
||||
- cp target/release/parity-evm deb/usr/bin/parity-evm
|
||||
- cp target/release/ethstore deb/usr/bin/ethstore
|
||||
- cp target/release/ethkey deb/usr/bin/ethkey
|
||||
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
|
||||
- dpkg-deb -b deb "parity_"$VER"_amd64.deb"
|
||||
- md5sum "parity_"$VER"_amd64.deb" > "parity_"$VER"_amd64.deb.md5"
|
||||
- aws configure set aws_access_key_id $s3_key
|
||||
- aws configure set aws_secret_access_key $s3_secret
|
||||
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable|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 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_"$VER"_amd64.deb" --body "parity_"$VER"_amd64.deb"
|
||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/"parity_"$VER"_amd64.deb.md5" --body "parity_"$VER"_amd64.deb.md5"
|
||||
- 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
|
||||
# ARGUMENTS: 1. BUILD_PLATFORM (target for binaries) 2. PLATFORM (target for cargo) 3. ARC (architecture) 4. & 5. CC & CXX flags 6. binary identifier
|
||||
- scripts/gitlab-build.sh x86_64-unknown-linux-gnu x86_64-unknown-linux-gnu amd64 gcc g++ ubuntu
|
||||
tags:
|
||||
- rust
|
||||
- rust-stable
|
||||
artifacts:
|
||||
paths:
|
||||
- target/release/parity
|
||||
- target/release/parity-evm
|
||||
- target/release/ethstore
|
||||
- target/release/ethkey
|
||||
- parity.zip
|
||||
name: "stable-x86_64-unknown-linux-gnu_parity"
|
||||
linux-snap:
|
||||
stage: build
|
||||
image: parity/snapcraft:gitlab-ci
|
||||
only:
|
||||
- snap
|
||||
- beta
|
||||
- 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_"$CI_BUILD"_REF_NAME_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"
|
||||
allow_failure: true
|
||||
linux-stable-debian:
|
||||
stage: build
|
||||
image: parity/rust-debian:gitlab-ci
|
||||
@@ -102,81 +43,14 @@ linux-stable-debian:
|
||||
- stable
|
||||
- triggers
|
||||
script:
|
||||
- cargo build -j $(nproc) --release --features final $CARGOFLAGS
|
||||
- cargo build -j $(nproc) --release -p evmbin
|
||||
- cargo build -j $(nproc) --release -p ethstore-cli
|
||||
- cargo build -j $(nproc) --release -p ethkey-cli
|
||||
- strip target/release/parity
|
||||
- strip target/release/parity-evm
|
||||
- strip target/release/ethstore
|
||||
- strip target/release/ethkey
|
||||
- export SHA3=$(target/release/parity tools hash target/release/parity)
|
||||
- md5sum target/release/parity > parity.md5
|
||||
- sh scripts/deb-build.sh amd64
|
||||
- cp target/release/parity deb/usr/bin/parity
|
||||
- cp target/release/parity-evm deb/usr/bin/parity-evm
|
||||
- cp target/release/ethstore deb/usr/bin/ethstore
|
||||
- cp target/release/ethkey deb/usr/bin/ethkey
|
||||
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
|
||||
- dpkg-deb -b deb "parity_"$VER"_amd64.deb"
|
||||
- md5sum "parity_"$VER"_amd64.deb" > "parity_"$VER"_amd64.deb.md5"
|
||||
- aws configure set aws_access_key_id $s3_key
|
||||
- aws configure set aws_secret_access_key $s3_secret
|
||||
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable|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 s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-debian-gnu/parity --body target/release/parity
|
||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-debian-gnu/parity.md5 --body parity.md5
|
||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-debian-gnu/"parity_"$VER"_amd64.deb" --body "parity_"$VER"_amd64.deb"
|
||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-debian-gnu/"parity_"$VER"_amd64.deb.md5" --body "parity_"$VER"_amd64.deb.md5"
|
||||
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1337/push-build/$CI_BUILD_REF_NAME/x86_64-unknown-debian-gnu
|
||||
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1338/push-build/$CI_BUILD_REF_NAME/x86_64-unknown-debian-gnu
|
||||
- export LIBSSL="libssl1.1 (>=1.1.0)"
|
||||
- scripts/gitlab-build.sh x86_64-unknown-debian-gnu x86_64-unknown-linux-gnu amd64 gcc g++ debian
|
||||
tags:
|
||||
- rust
|
||||
- rust-debian
|
||||
artifacts:
|
||||
paths:
|
||||
- target/release/parity
|
||||
- parity.zip
|
||||
name: "stable-x86_64-unknown-debian-gnu_parity"
|
||||
linux-beta:
|
||||
stage: build
|
||||
image: parity/rust:gitlab-ci
|
||||
only:
|
||||
- beta
|
||||
- tags
|
||||
- stable
|
||||
- triggers
|
||||
script:
|
||||
- rustup default beta
|
||||
- cargo build -j $(nproc) --release $CARGOFLAGS
|
||||
- strip target/release/parity
|
||||
tags:
|
||||
- rust
|
||||
- rust-beta
|
||||
artifacts:
|
||||
paths:
|
||||
- target/release/parity
|
||||
name: "beta-x86_64-unknown-linux-gnu_parity"
|
||||
allow_failure: true
|
||||
linux-nightly:
|
||||
stage: build
|
||||
image: parity/rust:gitlab-ci
|
||||
only:
|
||||
- beta
|
||||
- tags
|
||||
- stable
|
||||
- triggers
|
||||
script:
|
||||
- rustup default nightly
|
||||
- cargo build -j $(nproc) --release $CARGOFLAGS
|
||||
- strip target/release/parity
|
||||
tags:
|
||||
- rust
|
||||
- rust-nightly
|
||||
artifacts:
|
||||
paths:
|
||||
- target/release/parity
|
||||
name: "nigthly-x86_64-unknown-linux-gnu_parity"
|
||||
allow_failure: true
|
||||
linux-centos:
|
||||
stage: build
|
||||
image: parity/rust-centos:gitlab-ci
|
||||
@@ -186,42 +60,12 @@ linux-centos:
|
||||
- stable
|
||||
- triggers
|
||||
script:
|
||||
- export CXX="g++"
|
||||
- export CC="gcc"
|
||||
- export PLATFORM=x86_64-unknown-centos-gnu
|
||||
- cargo build -j $(nproc) --release --features final $CARGOFLAGS
|
||||
- cargo build -j $(nproc) --release -p evmbin
|
||||
- cargo build -j $(nproc) --release -p ethstore-cli
|
||||
- cargo build -j $(nproc) --release -p ethkey-cli
|
||||
- strip target/release/parity
|
||||
- strip target/release/parity-evm
|
||||
- strip target/release/ethstore
|
||||
- strip target/release/ethkey
|
||||
- md5sum target/release/parity > parity.md5
|
||||
- md5sum target/release/parity-evm > parity-evm.md5
|
||||
- md5sum target/release/ethstore > ethstore.md5
|
||||
- md5sum target/release/ethkey > ethkey.md5
|
||||
- export SHA3=$(target/release/parity tools hash target/release/parity)
|
||||
- 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 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.md5 --body parity.md5
|
||||
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/parity-evm --body target/release/parity-evm
|
||||
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/parity-evm.md5 --body parity-evm.md5
|
||||
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/ethstore --body target/release/ethstore
|
||||
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/ethstore.md5 --body ethstore.md5
|
||||
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/ethkey --body target/release/ethkey
|
||||
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/ethkey.md5 --body ethkey.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:1338/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
||||
- scripts/gitlab-build.sh x86_64-unknown-centos-gnu x86_64-unknown-linux-gnu x86_64 gcc g++ centos
|
||||
tags:
|
||||
- rust
|
||||
- rust-centos
|
||||
artifacts:
|
||||
paths:
|
||||
- target/release/parity
|
||||
- parity.zip
|
||||
name: "x86_64-unknown-centos-gnu_parity"
|
||||
linux-i686:
|
||||
stage: build
|
||||
@@ -232,47 +76,13 @@ linux-i686:
|
||||
- stable
|
||||
- triggers
|
||||
script:
|
||||
- export HOST_CC=gcc
|
||||
- export HOST_CXX=g++
|
||||
- export COMMIT=$(git rev-parse HEAD)
|
||||
- export PLATFORM=i686-unknown-linux-gnu
|
||||
- cargo build -j $(nproc) --target $PLATFORM --features final --release $CARGOFLAGS
|
||||
- cargo build -j $(nproc) --target $PLATFORM --release -p evmbin
|
||||
- cargo build -j $(nproc) --target $PLATFORM --release -p ethstore-cli
|
||||
- cargo build -j $(nproc) --target $PLATFORM --release -p ethkey-cli
|
||||
- strip target/$PLATFORM/release/parity
|
||||
- strip target/$PLATFORM/release/parity-evm
|
||||
- strip target/$PLATFORM/release/ethstore
|
||||
- strip target/$PLATFORM/release/ethkey
|
||||
- strip target/$PLATFORM/release/parity
|
||||
- md5sum target/$PLATFORM/release/parity > parity.md5
|
||||
- export SHA3=$(target/$PLATFORM/release/parity tools hash target/$PLATFORM/release/parity)
|
||||
- sh scripts/deb-build.sh i386
|
||||
- cp target/$PLATFORM/release/parity deb/usr/bin/parity
|
||||
- cp target/$PLATFORM/release/parity-evm deb/usr/bin/parity-evm
|
||||
- cp target/$PLATFORM/release/ethstore deb/usr/bin/ethstore
|
||||
- cp target/$PLATFORM/release/ethkey deb/usr/bin/ethkey
|
||||
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
|
||||
- dpkg-deb -b deb "parity_"$VER"_i386.deb"
|
||||
- md5sum "parity_"$VER"_i386.deb" > "parity_"$VER"_i386.deb.md5"
|
||||
- aws configure set aws_access_key_id $s3_key
|
||||
- aws configure set aws_secret_access_key $s3_secret
|
||||
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable|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 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_"$VER"_i386.deb" --body "parity_"$VER"_i386.deb"
|
||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_i386.deb.md5" --body "parity_"$VER"_i386.deb.md5"
|
||||
- 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
|
||||
- scripts/gitlab-build.sh i686-unknown-linux-gnu i686-unknown-linux-gnu i386 gcc g++ ubuntu
|
||||
tags:
|
||||
- rust
|
||||
- rust-i686
|
||||
artifacts:
|
||||
paths:
|
||||
- target/i686-unknown-linux-gnu/release/parity
|
||||
- parity.zip
|
||||
name: "i686-unknown-linux-gnu"
|
||||
allow_failure: true
|
||||
linux-armv7:
|
||||
stage: build
|
||||
image: parity/rust-armv7:gitlab-ci
|
||||
@@ -282,55 +92,13 @@ linux-armv7:
|
||||
- stable
|
||||
- triggers
|
||||
script:
|
||||
- export CC=arm-linux-gnueabihf-gcc
|
||||
- export CXX=arm-linux-gnueabihf-g++
|
||||
- export HOST_CC=gcc
|
||||
- export HOST_CXX=g++
|
||||
- export PLATFORM=armv7-unknown-linux-gnueabihf
|
||||
- rm -rf .cargo
|
||||
- mkdir -p .cargo
|
||||
- echo "[target.$PLATFORM]" >> .cargo/config
|
||||
- echo "linker= \"arm-linux-gnueabihf-gcc\"" >> .cargo/config
|
||||
- cat .cargo/config
|
||||
- cargo build -j $(nproc) --target $PLATFORM --features final --release $CARGOFLAGS
|
||||
- cargo build -j $(nproc) --target $PLATFORM --release -p evmbin
|
||||
- cargo build -j $(nproc) --target $PLATFORM --release -p ethstore-cli
|
||||
- cargo build -j $(nproc) --target $PLATFORM --release -p ethkey-cli
|
||||
- md5sum target/$PLATFORM/release/parity > parity.md5
|
||||
- export SHA3=$(target/$PLATFORM/release/parity tools hash target/$PLATFORM/release/parity)
|
||||
- sh scripts/deb-build.sh i386
|
||||
- arm-linux-gnueabihf-strip target/$PLATFORM/release/parity
|
||||
- arm-linux-gnueabihf-strip target/$PLATFORM/release/parity-evm
|
||||
- arm-linux-gnueabihf-strip target/$PLATFORM/release/ethstore
|
||||
- arm-linux-gnueabihf-strip target/$PLATFORM/release/ethkey
|
||||
- export SHA3=$(rhash --sha3-256 target/$PLATFORM/release/parity -p %h)
|
||||
- md5sum target/$PLATFORM/release/parity > parity.md5
|
||||
- sh scripts/deb-build.sh armhf
|
||||
- cp target/$PLATFORM/release/parity deb/usr/bin/parity
|
||||
- cp target/$PLATFORM/release/parity-evm deb/usr/bin/parity-evm
|
||||
- cp target/$PLATFORM/release/ethstore deb/usr/bin/ethstore
|
||||
- cp target/$PLATFORM/release/ethkey deb/usr/bin/ethkey
|
||||
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
|
||||
- dpkg-deb -b deb "parity_"$VER"_armhf.deb"
|
||||
- md5sum "parity_"$VER"_armhf.deb" > "parity_"$VER"_armhf.deb.md5"
|
||||
- aws configure set aws_access_key_id $s3_key
|
||||
- aws configure set aws_secret_access_key $s3_secret
|
||||
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable|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 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_"$VER"_armhf.deb" --body "parity_"$VER"_armhf.deb"
|
||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_armhf.deb.md5" --body "parity_"$VER"_armhf.deb.md5"
|
||||
- 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
|
||||
- scripts/gitlab-build.sh armv7-unknown-linux-gnueabihf armv7-unknown-linux-gnueabihf armhf arm-linux-gnueabihf-gcc arm-linux-gnueabihf-g++ ubuntu
|
||||
tags:
|
||||
- rust
|
||||
- rust-arm
|
||||
artifacts:
|
||||
paths:
|
||||
- target/armv7-unknown-linux-gnueabihf/release/parity
|
||||
- parity.zip
|
||||
name: "armv7_unknown_linux_gnueabihf_parity"
|
||||
allow_failure: true
|
||||
linux-arm:
|
||||
stage: build
|
||||
image: parity/rust-arm:gitlab-ci
|
||||
@@ -340,52 +108,13 @@ linux-arm:
|
||||
- stable
|
||||
- triggers
|
||||
script:
|
||||
- export CC=arm-linux-gnueabihf-gcc
|
||||
- export CXX=arm-linux-gnueabihf-g++
|
||||
- export HOST_CC=gcc
|
||||
- export HOST_CXX=g++
|
||||
- export PLATFORM=arm-unknown-linux-gnueabihf
|
||||
- rm -rf .cargo
|
||||
- mkdir -p .cargo
|
||||
- echo "[target.$PLATFORM]" >> .cargo/config
|
||||
- echo "linker= \"arm-linux-gnueabihf-gcc\"" >> .cargo/config
|
||||
- cat .cargo/config
|
||||
- cargo build -j $(nproc) --target $PLATFORM --features final --release $CARGOFLAGS
|
||||
- cargo build -j $(nproc) --target $PLATFORM --release -p evmbin
|
||||
- cargo build -j $(nproc) --target $PLATFORM --release -p ethstore-cli
|
||||
- cargo build -j $(nproc) --target $PLATFORM --release -p ethkey-cli
|
||||
- arm-linux-gnueabihf-strip target/$PLATFORM/release/parity
|
||||
- arm-linux-gnueabihf-strip target/$PLATFORM/release/parity-evm
|
||||
- arm-linux-gnueabihf-strip target/$PLATFORM/release/ethstore
|
||||
- arm-linux-gnueabihf-strip target/$PLATFORM/release/ethkey
|
||||
- export SHA3=$(rhash --sha3-256 target/$PLATFORM/release/parity -p %h)
|
||||
- md5sum target/$PLATFORM/release/parity > parity.md5
|
||||
- sh scripts/deb-build.sh armhf
|
||||
- cp target/$PLATFORM/release/parity deb/usr/bin/parity
|
||||
- cp target/$PLATFORM/release/parity-evm deb/usr/bin/parity-evm
|
||||
- cp target/$PLATFORM/release/ethstore deb/usr/bin/ethstore
|
||||
- cp target/$PLATFORM/release/ethkey deb/usr/bin/ethkey
|
||||
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
|
||||
- dpkg-deb -b deb "parity_"$VER"_armhf.deb"
|
||||
- md5sum "parity_"$VER"_armhf.deb" > "parity_"$VER"_armhf.deb.md5"
|
||||
- aws configure set aws_access_key_id $s3_key
|
||||
- aws configure set aws_secret_access_key $s3_secret
|
||||
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable|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 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_"$VER"_armhf.deb" --body "parity_"$VER"_armhf.deb"
|
||||
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_armhf.deb.md5" --body "parity_"$VER"_armhf.deb.md5"
|
||||
- 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
|
||||
- scripts/gitlab-build.sh arm-unknown-linux-gnueabihf arm-unknown-linux-gnueabihf armhf arm-linux-gnueabihf-gcc arm-linux-gnueabihf-g++ ubuntu
|
||||
tags:
|
||||
- rust
|
||||
- rust-arm
|
||||
artifacts:
|
||||
paths:
|
||||
- target/arm-unknown-linux-gnueabihf/release/parity
|
||||
- parity.zip
|
||||
name: "arm-unknown-linux-gnueabihf_parity"
|
||||
allow_failure: true
|
||||
linux-aarch64:
|
||||
stage: build
|
||||
image: parity/rust-arm64:gitlab-ci
|
||||
@@ -395,50 +124,29 @@ linux-aarch64:
|
||||
- stable
|
||||
- triggers
|
||||
script:
|
||||
- export CC=aarch64-linux-gnu-gcc
|
||||
- export CXX=aarch64-linux-gnu-g++
|
||||
- export HOST_CC=gcc
|
||||
- export HOST_CXX=g++
|
||||
- export PLATFORM=aarch64-unknown-linux-gnu
|
||||
- rm -rf .cargo
|
||||
- mkdir -p .cargo
|
||||
- echo "[target.$PLATFORM]" >> .cargo/config
|
||||
- echo "linker= \"aarch64-linux-gnu-gcc\"" >> .cargo/config
|
||||
- cat .cargo/config
|
||||
- cargo build -j $(nproc) --target $PLATFORM --features final --release $CARGOFLAGS
|
||||
- cargo build -j $(nproc) --target $PLATFORM --release -p evmbin
|
||||
- cargo build -j $(nproc) --target $PLATFORM --release -p ethstore-cli
|
||||
- cargo build -j $(nproc) --target $PLATFORM --release -p ethkey-cli
|
||||
- aarch64-linux-gnu-strip target/$PLATFORM/release/parity
|
||||
- aarch64-linux-gnu-strip target/$PLATFORM/release/parity-evm
|
||||
- aarch64-linux-gnu-strip target/$PLATFORM/release/ethstore
|
||||
- aarch64-linux-gnu-strip target/$PLATFORM/release/ethkey
|
||||
- export SHA3=$(rhash --sha3-256 target/$PLATFORM/release/parity -p %h)
|
||||
- md5sum target/$PLATFORM/release/parity > parity.md5
|
||||
- sh scripts/deb-build.sh arm64
|
||||
- cp target/$PLATFORM/release/parity deb/usr/bin/parity
|
||||
- cp target/$PLATFORM/release/parity-evm deb/usr/bin/parity-evm
|
||||
- cp target/$PLATFORM/release/ethstore deb/usr/bin/ethstore
|
||||
- cp target/$PLATFORM/release/ethkey deb/usr/bin/ethkey
|
||||
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
|
||||
- dpkg-deb -b deb "parity_"$VER"_arm64.deb"
|
||||
- md5sum "parity_"$VER"_arm64.deb" > "parity_"$VER"_arm64.deb.md5"
|
||||
- aws configure set aws_access_key_id $s3_key
|
||||
- aws configure set aws_secret_access_key $s3_secret
|
||||
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable|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 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.md5" --body "parity_"$VER"_arm64.deb.md5"
|
||||
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
||||
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://update.parity.io:1338/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
||||
- scripts/gitlab-build.sh aarch64-unknown-linux-gnu aarch64-unknown-linux-gnu arm64 aarch64-linux-gnu-gcc aarch64-linux-gnu-g++ ubuntu
|
||||
tags:
|
||||
- rust
|
||||
- rust-arm
|
||||
artifacts:
|
||||
paths:
|
||||
- target/aarch64-unknown-linux-gnu/release/parity
|
||||
- parity.zip
|
||||
name: "aarch64-unknown-linux-gnu_parity"
|
||||
linux-snap:
|
||||
stage: build
|
||||
image: snapcore/snapcraft:stable
|
||||
only:
|
||||
- stable
|
||||
- beta
|
||||
- tags
|
||||
- triggers
|
||||
script:
|
||||
- scripts/gitlab-build.sh x86_64-unknown-snap-gnu x86_64-unknown-linux-gnu amd64 gcc g++ snap
|
||||
tags:
|
||||
- rust-stable
|
||||
artifacts:
|
||||
paths:
|
||||
- parity.zip
|
||||
name: "stable-x86_64-unknown-snap-gnu_parity"
|
||||
allow_failure: true
|
||||
darwin:
|
||||
stage: build
|
||||
@@ -447,45 +155,17 @@ darwin:
|
||||
- tags
|
||||
- stable
|
||||
- triggers
|
||||
script: |
|
||||
export COMMIT=$(git rev-parse HEAD)
|
||||
export PLATFORM=x86_64-apple-darwin
|
||||
rustup default stable
|
||||
cargo clean
|
||||
cargo build -j 8 --features final --release #$CARGOFLAGS
|
||||
cargo build -j 8 --release -p ethstore-cli #$CARGOFLAGS
|
||||
cargo build -j 8 --release -p ethkey-cli #$CARGOFLAGS
|
||||
cargo build -j 8 --release -p evmbin #$CARGOFLAGS
|
||||
rm -rf parity.md5
|
||||
md5sum target/release/parity > parity.md5
|
||||
export SHA3=$(target/release/parity tools hash target/release/parity)
|
||||
cd mac
|
||||
xcodebuild -configuration Release
|
||||
cd ..
|
||||
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
|
||||
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"-macos-installer.pkg"
|
||||
md5sum "parity-"$VER"-macos-installer.pkg" >> "parity-"$VER"-macos-installer.pkg.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 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.md5 --body parity.md5
|
||||
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity-"$VER"-macos-installer.pkg" --body "parity-"$VER"-macos-installer.pkg"
|
||||
aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity-"$VER"-macos-installer.pkg.md5" --body "parity-"$VER"-macos-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:1338/push-build/$CI_BUILD_REF_NAME/$PLATFORM
|
||||
script:
|
||||
- scripts/gitlab-build.sh x86_64-apple-darwin x86_64-apple-darwin macos gcc g++ macos
|
||||
tags:
|
||||
- osx
|
||||
artifacts:
|
||||
paths:
|
||||
- target/release/parity
|
||||
- parity.zip
|
||||
name: "x86_64-apple-darwin_parity"
|
||||
windows:
|
||||
cache:
|
||||
key: "%CI_BUILD_STAGE%/%CI_BUILD_REF_NAME%"
|
||||
key: "%CI_BUILD_STAGE%-%CI_BUILD_REF_NAME%"
|
||||
untracked: true
|
||||
stage: build
|
||||
only:
|
||||
@@ -494,62 +174,12 @@ windows:
|
||||
- stable
|
||||
- triggers
|
||||
script:
|
||||
- set PLATFORM=x86_64-pc-windows-msvc
|
||||
- set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include;C:\vs2015\VC\include;C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt
|
||||
- set LIB=C:\vs2015\VC\lib;C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10240.0\ucrt\x64
|
||||
- set RUST_BACKTRACE=1
|
||||
- set RUSTFLAGS=%RUSTFLAGS%
|
||||
- rustup default stable-x86_64-pc-windows-msvc
|
||||
- cargo clean
|
||||
- cargo build --features final --release #%CARGOFLAGS%
|
||||
- cargo build --release -p ethstore-cli #%CARGOFLAGS%
|
||||
- cargo build --release -p ethkey-cli #%CARGOFLAGS%
|
||||
- cargo build --release -p evmbin #%CARGOFLAGS%
|
||||
- signtool sign /f %keyfile% /p %certpass% target\release\parity.exe
|
||||
- target\release\parity.exe tools hash target\release\parity.exe > parity.sha3
|
||||
- set /P SHA3=<parity.sha3
|
||||
- curl -sL --url "https://github.com/paritytech/win-build/raw/master/SimpleFC.dll" -o nsis\SimpleFC.dll
|
||||
- curl -sL --url "https://github.com/paritytech/win-build/raw/master/vc_redist.x64.exe" -o nsis\vc_redist.x64.exe
|
||||
- msbuild windows\ptray\ptray.vcxproj /p:Platform=x64 /p:Configuration=Release
|
||||
- signtool sign /f %keyfile% /p %certpass% windows\ptray\x64\release\ptray.exe
|
||||
- cd nsis
|
||||
- makensis.exe installer.nsi
|
||||
- copy installer.exe InstallParity.exe
|
||||
- signtool sign /f %keyfile% /p %certpass% InstallParity.exe
|
||||
- md5sums InstallParity.exe > InstallParity.exe.md5
|
||||
- zip win-installer.zip InstallParity.exe InstallParity.exe.md5
|
||||
- md5sums win-installer.zip > win-installer.zip.md5
|
||||
- cd ..\target\release\
|
||||
- md5sums parity.exe > parity.exe.md5
|
||||
- zip parity.zip parity.exe parity.md5
|
||||
- md5sums parity.zip > parity.zip.md5
|
||||
- cd ..\..
|
||||
- aws configure set aws_access_key_id %s3_key%
|
||||
- aws configure set aws_secret_access_key %s3_secret%
|
||||
- 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 "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 "nightly" >nul 2>&1 && set S3_BUCKET=builds-parity-published|| set S3_BUCKET=builds-parity
|
||||
- echo %S3_BUCKET%
|
||||
- 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.md5 --body target\release\parity.exe.md5
|
||||
- aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.zip --body target\release\parity.zip
|
||||
- aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.zip.md5 --body target\release\parity.zip.md5
|
||||
- aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/InstallParity.exe --body nsis\InstallParity.exe
|
||||
- aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/InstallParity.exe.md5 --body nsis\InstallParity.exe.md5
|
||||
- aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/win-installer.zip --body nsis\win-installer.zip
|
||||
- aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/win-installer.zip.md5 --body nsis\win-installer.zip.md5
|
||||
- curl --data "commit=%CI_BUILD_REF%&sha3=%SHA3%&filename=parity.exe&secret=%RELEASES_SECRET%" http://update.parity.io:1337/push-build/%CI_BUILD_REF_NAME%/%PLATFORM%
|
||||
- curl --data "commit=%CI_BUILD_REF%&sha3=%SHA3%&filename=parity.exe&secret=%RELEASES_SECRET%" http://update.parity.io:1338/push-build/%CI_BUILD_REF_NAME%/%PLATFORM%
|
||||
- sh scripts/gitlab-build.sh x86_64-pc-windows-msvc x86_64-pc-windows-msvc installer "" "" windows
|
||||
tags:
|
||||
- rust-windows
|
||||
artifacts:
|
||||
paths:
|
||||
- target/release/parity.exe
|
||||
- target/release/parity.pdb
|
||||
- nsis/InstallParity.exe
|
||||
- parity.zip
|
||||
name: "x86_64-pc-windows-msvc_parity"
|
||||
docker-build:
|
||||
stage: build
|
||||
@@ -562,7 +192,7 @@ docker-build:
|
||||
- if [ "$CI_BUILD_REF_NAME" == "beta-release" ]; then DOCKER_TAG="latest"; else DOCKER_TAG=$CI_BUILD_REF_NAME; fi
|
||||
- echo "Tag:" $DOCKER_TAG
|
||||
- docker login -u $Docker_Hub_User_Parity -p $Docker_Hub_Pass_Parity
|
||||
- sh scripts/docker-build.sh $DOCKER_TAG
|
||||
- scripts/docker-build.sh $DOCKER_TAG
|
||||
- docker logout
|
||||
tags:
|
||||
- docker
|
||||
@@ -571,63 +201,16 @@ test-coverage:
|
||||
only:
|
||||
- master
|
||||
script:
|
||||
- git submodule update --init --recursive
|
||||
- rm -rf target/*
|
||||
- rm -rf js/.coverage
|
||||
- scripts/cov.sh
|
||||
# - COVERAGE=$(grep -Po 'covered":.*?[^\\]"' target/cov/index.json | grep "[0-9]*\.[0-9]" -o)
|
||||
# - echo "Coverage:" $COVERAGE
|
||||
- scripts/gitlab-test.sh test-coverage
|
||||
tags:
|
||||
- kcov
|
||||
allow_failure: true
|
||||
test-darwin:
|
||||
stage: test
|
||||
only:
|
||||
- triggers
|
||||
variables:
|
||||
RUST_BACKTRACE: 1
|
||||
script:
|
||||
- git submodule update --init --recursive
|
||||
- if [ $RUST_FILES_MODIFIED -eq 0 ]; then echo "Skipping Rust tests since no Rust files modified."; else ./test.sh $CARGOFLAGS; fi
|
||||
tags:
|
||||
- osx
|
||||
allow_failure: true
|
||||
test-windows:
|
||||
stage: test
|
||||
only:
|
||||
- triggers
|
||||
variables:
|
||||
RUST_BACKTRACE: 1
|
||||
script:
|
||||
- git submodule update --init --recursive
|
||||
- echo cargo test --features json-tests -p rlp -p ethash -p ethcore -p ethcore-bigint -p parity-dapps -p parity-rpc -p ethcore-util -p ethcore-network -p ethcore-io -p ethkey -p ethstore -p ethsync -p ethcore-ipc -p ethcore-ipc-tests -p ethcore-ipc-nano -p parity-rpc-client -p parity %CARGOFLAGS% --verbose --release
|
||||
tags:
|
||||
- rust-windows
|
||||
allow_failure: true
|
||||
test-rust-stable:
|
||||
stage: test
|
||||
image: parity/rust:gitlab-ci
|
||||
variables:
|
||||
RUST_BACKTRACE: 1
|
||||
script:
|
||||
- git submodule update --init --recursive
|
||||
- rustup show
|
||||
- if [ $RUST_FILES_MODIFIED -eq 0 ]; then echo "Skipping Rust tests since no Rust files modified."; else ./test.sh $CARGOFLAGS; fi
|
||||
- if [ "$CI_BUILD_REF_NAME" == "nightly" ]; then sh scripts/aura-test.sh; fi
|
||||
- scripts/gitlab-test.sh stable
|
||||
tags:
|
||||
- rust
|
||||
- rust-stable
|
||||
js-test:
|
||||
stage: test
|
||||
image: parity/rust:gitlab-ci
|
||||
script:
|
||||
- git submodule update --init --recursive
|
||||
- if [ $JS_FILES_MODIFIED -eq 0 ]; then echo "Skipping JS deps install since no JS files modified."; else ./js/scripts/install-deps.sh;fi
|
||||
- if [ $JS_OLD_FILES_MODIFIED -eq 0 ]; then echo "Skipping JS (old) deps install since no JS files modified."; else ./js-old/scripts/install-deps.sh;fi
|
||||
- if [ $JS_FILES_MODIFIED -eq 0 ]; then echo "Skipping JS lint since no JS files modified."; else ./js/scripts/lint.sh && ./js/scripts/test.sh && ./js/scripts/build.sh; fi
|
||||
- if [ $JS_OLD_FILES_MODIFIED -eq 0 ]; then echo "Skipping JS (old) lint since no JS files modified."; else ./js-old/scripts/lint.sh && ./js-old/scripts/test.sh && ./js-old/scripts/build.sh; fi
|
||||
tags:
|
||||
- rust
|
||||
- rust-stable
|
||||
test-rust-beta:
|
||||
stage: test
|
||||
@@ -635,14 +218,9 @@ test-rust-beta:
|
||||
- triggers
|
||||
- master
|
||||
image: parity/rust:gitlab-ci
|
||||
variables:
|
||||
RUST_BACKTRACE: 1
|
||||
script:
|
||||
- git submodule update --init --recursive
|
||||
- rustup default beta
|
||||
- if [ $RUST_FILES_MODIFIED -eq 0 ]; then echo "Skipping Rust tests since no Rust files modified."; else ./test.sh $CARGOFLAGS; fi
|
||||
- scripts/gitlab-test.sh beta
|
||||
tags:
|
||||
- rust
|
||||
- rust-beta
|
||||
allow_failure: true
|
||||
test-rust-nightly:
|
||||
@@ -651,36 +229,30 @@ test-rust-nightly:
|
||||
- triggers
|
||||
- master
|
||||
image: parity/rust:gitlab-ci
|
||||
variables:
|
||||
RUST_BACKTRACE: 1
|
||||
script:
|
||||
- git submodule update --init --recursive
|
||||
- rustup default nightly
|
||||
- if [ $RUST_FILES_MODIFIED -eq 0 ]; then echo "Skipping Rust tests since no Rust files modified."; else ./test.sh $CARGOFLAGS; fi
|
||||
- scripts/gitlab-test.sh nightly
|
||||
tags:
|
||||
- rust
|
||||
- rust-nightly
|
||||
allow_failure: true
|
||||
js-test:
|
||||
stage: test
|
||||
image: parity/rust:gitlab-ci
|
||||
script:
|
||||
- scripts/gitlab-test.sh js-test
|
||||
tags:
|
||||
- rust-stable
|
||||
js-release:
|
||||
stage: js-build
|
||||
only:
|
||||
- master
|
||||
- beta
|
||||
- stable
|
||||
- beta
|
||||
- tags
|
||||
- triggers
|
||||
image: parity/rust:gitlab-ci
|
||||
script:
|
||||
- rustup default stable
|
||||
- echo $JS_FILES_MODIFIED
|
||||
- if [ $JS_FILES_MODIFIED -eq 0 ]; then echo "Skipping JS deps install since no JS files modified."; else ./js/scripts/install-deps.sh;fi
|
||||
- if [ $JS_FILES_MODIFIED -eq 0 ]; then echo "Skipping JS rebuild since no JS files modified."; else ./js/scripts/build.sh && ./js/scripts/push-precompiled.sh; fi
|
||||
|
||||
- echo $JS_OLD_FILES_MODIFIED
|
||||
- if [ $JS_OLD_FILES_MODIFIED -eq 0 ]; then echo "Skipping JS (old) deps install since no JS files modified."; else ./js-old/scripts/install-deps.sh;fi
|
||||
- if [ $JS_OLD_FILES_MODIFIED -eq 0 ]; then echo "Skipping JS (old) rebuild since no JS files modified."; else ./js-old/scripts/build.sh && ./js-old/scripts/push-precompiled.sh; fi
|
||||
|
||||
- if [ $JS_FILES_MODIFIED -eq 0 ] && [ $JS_OLD_FILES_MODIFIED -eq 0 ]; then echo "Skipping Cargo update since no JS files modified."; else ./js/scripts/push-cargo.sh; fi
|
||||
- scripts/gitlab-test.sh js-release
|
||||
tags:
|
||||
- javascript
|
||||
push-release:
|
||||
@@ -690,18 +262,6 @@ push-release:
|
||||
- triggers
|
||||
image: parity/rust:gitlab-ci
|
||||
script:
|
||||
- rustup default stable
|
||||
- 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
|
||||
- scripts/gitlab-push-release.sh
|
||||
tags:
|
||||
- curl
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
.functions: &functions |
|
||||
export JS_FILES_MODIFIED=$(git --no-pager diff --name-only master...$CI_BUILD_REF | grep ^js/ | wc -l)
|
||||
export JS_OLD_FILES_MODIFIED=$(git --no-pager diff --name-only master...$CI_BUILD_REF | grep ^js-old/ | wc -l)
|
||||
export RUST_FILES_MODIFIED=$(git --no-pager diff --name-only master...$CI_BUILD_REF | grep -v -e ^js -e ^\\. -e ^LICENSE -e ^README.md -e ^test.sh -e ^windows/ -e ^scripts/ -e^mac/ -e ^nsis/ | wc -l)
|
||||
|
||||
before_script:
|
||||
- *functions
|
||||
|
||||
|
||||
103
Cargo.lock
generated
@@ -25,6 +25,11 @@ name = "ansi_term"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "app_dirs"
|
||||
version = "1.1.1"
|
||||
@@ -163,6 +168,11 @@ name = "bitflags"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bloomable"
|
||||
version = "0.1.0"
|
||||
@@ -234,15 +244,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.26.2"
|
||||
version = "2.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"textwrap 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -596,7 +605,6 @@ dependencies = [
|
||||
"ethcore-io 1.9.0",
|
||||
"ethcore-network 1.9.0",
|
||||
"ethcore-util 1.9.0",
|
||||
"evm 0.1.0",
|
||||
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"heapsize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -663,6 +671,8 @@ dependencies = [
|
||||
"rlp 0.2.1",
|
||||
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)",
|
||||
@@ -1903,11 +1913,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "parity"
|
||||
version = "1.9.0"
|
||||
version = "1.9.3"
|
||||
dependencies = [
|
||||
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)",
|
||||
"daemonize 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dir 0.1.0",
|
||||
@@ -1951,7 +1961,7 @@ dependencies = [
|
||||
"parity-rpc 1.9.0",
|
||||
"parity-rpc-client 1.4.0",
|
||||
"parity-updater 1.9.0",
|
||||
"parity-version 1.9.0",
|
||||
"parity-version 1.9.3",
|
||||
"parity-whisper 0.1.0",
|
||||
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"path 0.1.0",
|
||||
@@ -1966,6 +1976,8 @@ dependencies = [
|
||||
"serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1997,7 +2009,7 @@ dependencies = [
|
||||
"parity-hash-fetch 1.9.0",
|
||||
"parity-reactor 0.1.0",
|
||||
"parity-ui 1.9.0",
|
||||
"parity-version 1.9.0",
|
||||
"parity-version 1.9.3",
|
||||
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2145,7 +2157,7 @@ dependencies = [
|
||||
"order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-reactor 0.1.0",
|
||||
"parity-updater 1.9.0",
|
||||
"parity-version 1.9.0",
|
||||
"parity-version 1.9.3",
|
||||
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2204,8 +2216,8 @@ version = "1.9.0"
|
||||
dependencies = [
|
||||
"parity-ui-dev 1.9.0",
|
||||
"parity-ui-old-dev 1.9.0",
|
||||
"parity-ui-old-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-9-v1.git)",
|
||||
"parity-ui-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-9-shell.git)",
|
||||
"parity-ui-old-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-beta-1-9-v1.git)",
|
||||
"parity-ui-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-beta-1-9-shell.git)",
|
||||
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -2226,7 +2238,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "parity-ui-old-precompiled"
|
||||
version = "1.9.0"
|
||||
source = "git+https://github.com/js-dist-paritytech/parity-master-1-9-v1.git#ae75b135453ed081a6beb7c2bf3e3aa2b9957f69"
|
||||
source = "git+https://github.com/js-dist-paritytech/parity-beta-1-9-v1.git#54398b761c19fbdfb47e3f2fc21eddec92f8ca40"
|
||||
dependencies = [
|
||||
"parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -2234,7 +2246,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "parity-ui-precompiled"
|
||||
version = "1.9.0"
|
||||
source = "git+https://github.com/js-dist-paritytech/parity-master-1-9-shell.git#47c6e031f8f5b16af8e1d99cb5c6f27055c0156d"
|
||||
source = "git+https://github.com/js-dist-paritytech/parity-beta-1-9-shell.git#266a67a3a0112efcdcfdd8b1ef0721a28575bbc7"
|
||||
dependencies = [
|
||||
"parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -2253,7 +2265,7 @@ dependencies = [
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-hash-fetch 1.9.0",
|
||||
"parity-reactor 0.1.0",
|
||||
"parity-version 1.9.0",
|
||||
"parity-version 1.9.3",
|
||||
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"path 0.1.0",
|
||||
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2262,23 +2274,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "parity-version"
|
||||
version = "1.9.0"
|
||||
version = "1.9.3"
|
||||
dependencies = [
|
||||
"ethcore-bytes 0.1.0",
|
||||
"rlp 0.2.1",
|
||||
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vergen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parity-wasm"
|
||||
version = "0.15.3"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2329,6 +2342,15 @@ dependencies = [
|
||||
"parking_lot_core 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot_core 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.2.6"
|
||||
@@ -2505,7 +2527,7 @@ dependencies = [
|
||||
name = "pwasm-run-test"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore-bigint 0.2.1",
|
||||
"ethcore-logger 1.9.0",
|
||||
"ethjson 0.1.0",
|
||||
@@ -2671,7 +2693,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rocksdb"
|
||||
version = "0.4.5"
|
||||
source = "git+https://github.com/paritytech/rust-rocksdb#166e14ed63cbd2e44b51267b8b98e4b89b0f236f"
|
||||
source = "git+https://github.com/paritytech/rust-rocksdb#ecf06adf3148ab10f6f7686b724498382ff4f36e"
|
||||
dependencies = [
|
||||
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"local-encoding 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2681,10 +2703,11 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rocksdb-sys"
|
||||
version = "0.3.0"
|
||||
source = "git+https://github.com/paritytech/rust-rocksdb#166e14ed63cbd2e44b51267b8b98e4b89b0f236f"
|
||||
source = "git+https://github.com/paritytech/rust-rocksdb#ecf06adf3148ab10f6f7686b724498382ff4f36e"
|
||||
dependencies = [
|
||||
"cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"local-encoding 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)",
|
||||
]
|
||||
|
||||
@@ -3112,10 +3135,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.8.0"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -3464,24 +3486,35 @@ dependencies = [
|
||||
"ethcore-bigint 0.2.1",
|
||||
"ethcore-logger 1.9.0",
|
||||
"ethcore-util 1.9.0",
|
||||
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-wasm 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-wasm 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vm 0.1.0",
|
||||
"wasm-utils 0.1.0 (git+https://github.com/paritytech/wasm-utils)",
|
||||
"wasmi 0.0.0 (git+https://github.com/pepyakin/wasmi)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-utils"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/paritytech/wasm-utils#3d59f7ca0661317bc66894a26b2a5a319fa5d229"
|
||||
source = "git+https://github.com/paritytech/wasm-utils#6fdc1c4ed47a6acb0a4774da505a416dd637bc6d"
|
||||
dependencies = [
|
||||
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-wasm 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-wasm 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmi"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/pepyakin/wasmi#551c99273042deaad869c17798060e2212deacab"
|
||||
dependencies = [
|
||||
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-wasm 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3555,6 +3588,7 @@ dependencies = [
|
||||
"checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45"
|
||||
"checksum advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a"
|
||||
"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
|
||||
"checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455"
|
||||
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
|
||||
"checksum app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7d1c0d48a81bbb13043847f957971f4d87c81542d80ece5e84ba3cba4058fd4"
|
||||
"checksum arrayvec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1c0250693b17316353df525fb088da32a8c18f84eb65d113dde31f5a76ed17b6"
|
||||
@@ -3573,6 +3607,7 @@ dependencies = [
|
||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||
"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4"
|
||||
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
|
||||
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
|
||||
"checksum bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f421095d2a76fc24cd3fb3f912b90df06be7689912b1bdb423caefae59c258d"
|
||||
"checksum bn 0.4.4 (git+https://github.com/paritytech/bn)" = "<none>"
|
||||
"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d"
|
||||
@@ -3580,7 +3615,7 @@ dependencies = [
|
||||
"checksum cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7db2f146208d7e0fbee761b09cd65a7f51ccc38705d4e7262dad4d73b12a76b1"
|
||||
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
|
||||
"checksum cid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "34aa7da06f10541fbca6850719cdaa8fa03060a5d2fb33840f149cf8133a00c7"
|
||||
"checksum clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3451e409013178663435d6f15fdb212f14ee4424a3d74f979d081d0a66b6f1f2"
|
||||
"checksum clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8f4a2b3bb7ef3c672d7c13d15613211d5a6976b6892c598b0fcb5d40765f19c2"
|
||||
"checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd"
|
||||
"checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299"
|
||||
"checksum cookie 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d53b80dde876f47f03cda35303e368a79b91c70b0d65ecba5fd5280944a08591"
|
||||
@@ -3695,11 +3730,12 @@ dependencies = [
|
||||
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
|
||||
"checksum parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "261c025c67ba416e9fe63aa9b3236520ce3c74cfbe43590c9cdcec4ccc8180e4"
|
||||
"checksum parity-tokio-ipc 0.1.5 (git+https://github.com/nikvolf/parity-tokio-ipc)" = "<none>"
|
||||
"checksum parity-ui-old-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-9-v1.git)" = "<none>"
|
||||
"checksum parity-ui-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-9-shell.git)" = "<none>"
|
||||
"checksum parity-wasm 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8431a184ad88cfbcd71a792aaca319cc7203a94300c26b8dce2d0df0681ea87d"
|
||||
"checksum parity-ui-old-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-beta-1-9-v1.git)" = "<none>"
|
||||
"checksum parity-ui-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-beta-1-9-shell.git)" = "<none>"
|
||||
"checksum parity-wasm 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ba4b1d4236b76694f6ab8d8d00cdbe1e37c6dd1b5c803d26721f27e097d4d9"
|
||||
"checksum parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0dec124478845b142f68b446cbee953d14d4b41f1bc0425024417720dce693"
|
||||
"checksum parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e"
|
||||
"checksum parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3e7f7c9857874e54afeb950eebeae662b1e51a2493666d2ea4c0a5d91dcf0412"
|
||||
"checksum parking_lot_core 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4f610cb9664da38e417ea3225f23051f589851999535290e077939838ab7a595"
|
||||
"checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356"
|
||||
"checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc"
|
||||
@@ -3784,7 +3820,7 @@ dependencies = [
|
||||
"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
|
||||
"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
|
||||
"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
|
||||
"checksum textwrap 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8e08afc40ae3459e4838f303e465aa50d823df8d7f83ca88108f6d3afe7edd"
|
||||
"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
|
||||
"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14"
|
||||
"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865"
|
||||
"checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520"
|
||||
@@ -3821,6 +3857,7 @@ dependencies = [
|
||||
"checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum wasm-utils 0.1.0 (git+https://github.com/paritytech/wasm-utils)" = "<none>"
|
||||
"checksum wasmi 0.0.0 (git+https://github.com/pepyakin/wasmi)" = "<none>"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
"checksum ws 0.7.1 (git+https://github.com/tomusdrw/ws-rs)" = "<none>"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
description = "Parity Ethereum client"
|
||||
name = "parity"
|
||||
version = "1.9.0"
|
||||
version = "1.9.3"
|
||||
license = "GPL-3.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
build = "build.rs"
|
||||
@@ -12,6 +12,8 @@ env_logger = "0.4"
|
||||
rustc-hex = "1.0"
|
||||
docopt = "0.8"
|
||||
clap = "2"
|
||||
term_size = "0.3"
|
||||
textwrap = "0.9"
|
||||
time = "0.1"
|
||||
num_cpus = "1.2"
|
||||
number_prefix = "0.2"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# [Parity](https://parity.io/) - fast, light, and robust Ethereum client
|
||||
# [Parity](https://parity.io/) - fast, light, and robust Ethereum client
|
||||
|
||||
[](https://gitlab.parity.io/parity/parity/commits/master)
|
||||
[](https://build.snapcraft.io/user/paritytech/parity)
|
||||
|
||||
@@ -14,12 +14,10 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use endpoint::EndpointInfo;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct App {
|
||||
pub id: String,
|
||||
pub id: Option<String>,
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub version: String,
|
||||
@@ -28,32 +26,14 @@ pub struct App {
|
||||
pub icon_url: String,
|
||||
#[serde(rename="localUrl")]
|
||||
pub local_url: Option<String>,
|
||||
#[serde(rename="allowJsEval")]
|
||||
pub allow_js_eval: Option<bool>,
|
||||
}
|
||||
|
||||
impl App {
|
||||
/// Creates `App` instance from `EndpointInfo` and `id`.
|
||||
pub fn from_info(id: &str, info: &EndpointInfo) -> Self {
|
||||
App {
|
||||
id: id.to_owned(),
|
||||
name: info.name.to_owned(),
|
||||
description: info.description.to_owned(),
|
||||
version: info.version.to_owned(),
|
||||
author: info.author.to_owned(),
|
||||
icon_url: info.icon_url.to_owned(),
|
||||
local_url: info.local_url.to_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<EndpointInfo> for App {
|
||||
fn into(self) -> EndpointInfo {
|
||||
EndpointInfo {
|
||||
name: self.name,
|
||||
description: self.description,
|
||||
version: self.version,
|
||||
author: self.author,
|
||||
icon_url: self.icon_url,
|
||||
local_url: self.local_url,
|
||||
}
|
||||
pub fn with_id(&self, id: &str) -> Self {
|
||||
let mut app = self.clone();
|
||||
app.id = Some(id.into());
|
||||
app
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ impl ContentValidator for Dapp {
|
||||
// First find manifest file
|
||||
let (mut manifest, manifest_dir) = Self::find_manifest(&mut zip)?;
|
||||
// Overwrite id to match hash
|
||||
manifest.id = id;
|
||||
manifest.id = Some(id);
|
||||
|
||||
// Unpack zip
|
||||
for i in 0..zip.len() {
|
||||
|
||||
@@ -319,12 +319,14 @@ mod tests {
|
||||
).allow_dapps(true);
|
||||
|
||||
let handler = local::Dapp::new(pool, path, EndpointInfo {
|
||||
id: None,
|
||||
name: "fake".into(),
|
||||
description: "".into(),
|
||||
version: "".into(),
|
||||
author: "".into(),
|
||||
icon_url: "".into(),
|
||||
local_url: Some("".into()),
|
||||
allow_js_eval: None,
|
||||
}, Default::default(), None);
|
||||
|
||||
// when
|
||||
|
||||
@@ -46,17 +46,18 @@ fn read_manifest(name: &str, mut path: PathBuf) -> EndpointInfo {
|
||||
// Try to deserialize manifest
|
||||
deserialize_manifest(s)
|
||||
})
|
||||
.map(Into::into)
|
||||
.unwrap_or_else(|e| {
|
||||
warn!(target: "dapps", "Cannot read manifest file at: {:?}. Error: {:?}", path, e);
|
||||
|
||||
EndpointInfo {
|
||||
id: None,
|
||||
name: name.into(),
|
||||
description: name.into(),
|
||||
version: "0.0.0".into(),
|
||||
author: "?".into(),
|
||||
icon_url: "icon.png".into(),
|
||||
local_url: None,
|
||||
allow_js_eval: Some(false),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -20,8 +20,13 @@ pub use apps::App as Manifest;
|
||||
pub const MANIFEST_FILENAME: &'static str = "manifest.json";
|
||||
|
||||
pub fn deserialize_manifest(manifest: String) -> Result<Manifest, String> {
|
||||
serde_json::from_str::<Manifest>(&manifest).map_err(|e| format!("{:?}", e))
|
||||
// TODO [todr] Manifest validation (especialy: id (used as path))
|
||||
let mut manifest = serde_json::from_str::<Manifest>(&manifest).map_err(|e| format!("{:?}", e))?;
|
||||
if manifest.id.is_none() {
|
||||
return Err("App 'id' is missing.".into());
|
||||
}
|
||||
manifest.allow_js_eval = Some(manifest.allow_js_eval.unwrap_or(false));
|
||||
|
||||
Ok(manifest)
|
||||
}
|
||||
|
||||
pub fn serialize_manifest(manifest: &Manifest) -> Result<String, String> {
|
||||
|
||||
@@ -44,7 +44,7 @@ pub const WEB_PATH: &'static str = "web";
|
||||
pub const URL_REFERER: &'static str = "__referer=";
|
||||
|
||||
pub fn utils(pool: CpuPool) -> Box<Endpoint> {
|
||||
Box::new(page::builtin::Dapp::new(pool, parity_ui::App::default()))
|
||||
Box::new(page::builtin::Dapp::new(pool, false, parity_ui::App::default()))
|
||||
}
|
||||
|
||||
pub fn ui(pool: CpuPool) -> Box<Endpoint> {
|
||||
@@ -76,9 +76,9 @@ pub fn all_endpoints<F: Fetch>(
|
||||
}
|
||||
|
||||
// NOTE [ToDr] Dapps will be currently embeded on 8180
|
||||
insert::<parity_ui::App>(&mut pages, "ui", Embeddable::Yes(embeddable.clone()), pool.clone());
|
||||
insert::<parity_ui::App>(&mut pages, "ui", Embeddable::Yes(embeddable.clone()), pool.clone(), true);
|
||||
// old version
|
||||
insert::<parity_ui::old::App>(&mut pages, "v1", Embeddable::Yes(embeddable.clone()), pool.clone());
|
||||
insert::<parity_ui::old::App>(&mut pages, "v1", Embeddable::Yes(embeddable.clone()), pool.clone(), true);
|
||||
|
||||
pages.insert("proxy".into(), ProxyPac::boxed(embeddable.clone(), dapps_domain.to_owned()));
|
||||
pages.insert(WEB_PATH.into(), Web::boxed(embeddable.clone(), web_proxy_tokens.clone(), fetch.clone()));
|
||||
@@ -86,10 +86,16 @@ pub fn all_endpoints<F: Fetch>(
|
||||
(local_endpoints, pages)
|
||||
}
|
||||
|
||||
fn insert<T : WebApp + Default + 'static>(pages: &mut Endpoints, id: &str, embed_at: Embeddable, pool: CpuPool) {
|
||||
fn insert<T : WebApp + Default + 'static>(
|
||||
pages: &mut Endpoints,
|
||||
id: &str,
|
||||
embed_at: Embeddable,
|
||||
pool: CpuPool,
|
||||
allow_js_eval: bool,
|
||||
) {
|
||||
pages.insert(id.to_owned(), Box::new(match embed_at {
|
||||
Embeddable::Yes(address) => page::builtin::Dapp::new_safe_to_embed(pool, T::default(), address),
|
||||
Embeddable::No => page::builtin::Dapp::new(pool, T::default()),
|
||||
Embeddable::Yes(address) => page::builtin::Dapp::new_safe_to_embed(pool, allow_js_eval, T::default(), address),
|
||||
Embeddable::No => page::builtin::Dapp::new(pool, allow_js_eval, T::default()),
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -37,16 +37,7 @@ impl EndpointPath {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct EndpointInfo {
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub version: String,
|
||||
pub author: String,
|
||||
pub icon_url: String,
|
||||
pub local_url: Option<String>,
|
||||
}
|
||||
|
||||
pub type EndpointInfo = ::apps::App;
|
||||
pub type Endpoints = BTreeMap<String, Box<Endpoint>>;
|
||||
pub type Response = Box<Future<Item=hyper::Response, Error=hyper::Error> + Send>;
|
||||
pub type Request = hyper::Request;
|
||||
|
||||
@@ -82,7 +82,7 @@ impl Into<hyper::Response> for ContentHandler {
|
||||
.with_status(self.code)
|
||||
.with_header(header::ContentType(self.mimetype))
|
||||
.with_body(self.content);
|
||||
add_security_headers(&mut res.headers_mut(), self.safe_to_embed_on);
|
||||
add_security_headers(&mut res.headers_mut(), self.safe_to_embed_on, false);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ impl Into<hyper::Response> for EchoHandler {
|
||||
.with_header(content_type.unwrap_or(header::ContentType::json()))
|
||||
.with_body(self.request.body());
|
||||
|
||||
add_security_headers(res.headers_mut(), None);
|
||||
add_security_headers(res.headers_mut(), None, false);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ use hyper::header;
|
||||
use {apps, address, Embeddable};
|
||||
|
||||
/// Adds security-related headers to the Response.
|
||||
pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embeddable) {
|
||||
pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embeddable, allow_js_eval: bool) {
|
||||
headers.set_raw("X-XSS-Protection", "1; mode=block");
|
||||
headers.set_raw("X-Content-Type-Options", "nosniff");
|
||||
|
||||
@@ -47,6 +47,8 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embedd
|
||||
|
||||
// Content Security Policy headers
|
||||
headers.set_raw("Content-Security-Policy", String::new()
|
||||
// Restrict everything to the same origin by default.
|
||||
+ "default-src 'self';"
|
||||
// Allow connecting to WS servers and HTTP(S) servers.
|
||||
// We could be more restrictive and allow only RPC server URL.
|
||||
+ "connect-src http: https: ws: wss:;"
|
||||
@@ -64,26 +66,29 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embedd
|
||||
+ "style-src 'self' 'unsafe-inline' data: blob: https:;"
|
||||
// Allow fonts from data: and HTTPS.
|
||||
+ "font-src 'self' data: https:;"
|
||||
// Allow inline scripts and scripts eval (webpack/jsconsole)
|
||||
// Disallow objects
|
||||
+ "object-src 'none';"
|
||||
// Allow scripts
|
||||
+ {
|
||||
let script_src = embeddable_on.as_ref()
|
||||
.map(|e| e.extra_script_src.iter()
|
||||
.map(|&(ref host, port)| address(host, port))
|
||||
.join(" ")
|
||||
).unwrap_or_default();
|
||||
let eval = if allow_js_eval { " 'unsafe-eval'" } else { "" };
|
||||
|
||||
&format!(
|
||||
"script-src 'self' 'unsafe-inline' 'unsafe-eval' {};",
|
||||
script_src
|
||||
"script-src 'self' {}{};",
|
||||
script_src,
|
||||
eval
|
||||
)
|
||||
}
|
||||
// Same restrictions as script-src with additional
|
||||
// blob: that is required for camera access (worker)
|
||||
+ "worker-src 'self' 'unsafe-inline' 'unsafe-eval' https: blob:;"
|
||||
// Restrict everything else to the same origin.
|
||||
+ "default-src 'self';"
|
||||
+ "worker-src 'self' https: blob:;"
|
||||
// Run in sandbox mode (although it's not fully safe since we allow same-origin and script)
|
||||
+ "sandbox allow-same-origin allow-forms allow-modals allow-popups allow-presentation allow-scripts;"
|
||||
// Disallow subitting forms from any dapps
|
||||
// Disallow submitting forms from any dapps
|
||||
+ "form-action 'none';"
|
||||
// Never allow mixed content
|
||||
+ "block-all-mixed-content;"
|
||||
|
||||
@@ -51,7 +51,7 @@ impl<R: io::Read> StreamingHandler<R> {
|
||||
.with_status(self.status)
|
||||
.with_header(header::ContentType(self.mimetype))
|
||||
.with_body(body);
|
||||
add_security_headers(&mut res.headers_mut(), self.safe_to_embed_on);
|
||||
add_security_headers(&mut res.headers_mut(), self.safe_to_embed_on, false);
|
||||
|
||||
(reader, res)
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ impl Endpoints {
|
||||
/// Returns a current list of app endpoints.
|
||||
pub fn list(&self) -> Vec<apps::App> {
|
||||
self.endpoints.read().iter().filter_map(|(ref k, ref e)| {
|
||||
e.info().map(|ref info| apps::App::from_info(k, info))
|
||||
e.info().map(|ref info| info.with_id(k))
|
||||
}).collect()
|
||||
}
|
||||
|
||||
|
||||
@@ -38,13 +38,14 @@ pub struct Dapp<T: WebApp + 'static> {
|
||||
|
||||
impl<T: WebApp + 'static> Dapp<T> {
|
||||
/// Creates new `Dapp` for builtin (compile time) Dapp.
|
||||
pub fn new(pool: CpuPool, app: T) -> Self {
|
||||
let info = app.info();
|
||||
pub fn new(pool: CpuPool, allow_js_eval: bool, app: T) -> Self {
|
||||
let mut info = EndpointInfo::from(app.info());
|
||||
info.allow_js_eval = Some(allow_js_eval);
|
||||
Dapp {
|
||||
pool,
|
||||
app,
|
||||
safe_to_embed_on: None,
|
||||
info: EndpointInfo::from(info),
|
||||
info,
|
||||
fallback_to_index_html: false,
|
||||
}
|
||||
}
|
||||
@@ -65,13 +66,14 @@ impl<T: WebApp + 'static> Dapp<T> {
|
||||
/// Creates new `Dapp` which can be safely used in iframe
|
||||
/// even from different origin. It might be dangerous (clickjacking).
|
||||
/// Use wisely!
|
||||
pub fn new_safe_to_embed(pool: CpuPool, app: T, address: Embeddable) -> Self {
|
||||
let info = app.info();
|
||||
pub fn new_safe_to_embed(pool: CpuPool, allow_js_eval: bool, app: T, address: Embeddable) -> Self {
|
||||
let mut info = EndpointInfo::from(app.info());
|
||||
info.allow_js_eval = Some(allow_js_eval);
|
||||
Dapp {
|
||||
pool,
|
||||
app,
|
||||
safe_to_embed_on: address,
|
||||
info: EndpointInfo::from(info),
|
||||
info,
|
||||
fallback_to_index_html: false,
|
||||
}
|
||||
}
|
||||
@@ -117,6 +119,7 @@ impl<T: WebApp> Endpoint for Dapp<T> {
|
||||
file,
|
||||
cache: PageCache::Disabled,
|
||||
safe_to_embed_on: self.safe_to_embed_on.clone(),
|
||||
allow_js_eval: self.info.allow_js_eval.clone().unwrap_or(false),
|
||||
}.into_response();
|
||||
|
||||
self.pool.spawn(reader).forget();
|
||||
@@ -128,12 +131,14 @@ impl<T: WebApp> Endpoint for Dapp<T> {
|
||||
impl From<Info> for EndpointInfo {
|
||||
fn from(info: Info) -> Self {
|
||||
EndpointInfo {
|
||||
id: None,
|
||||
name: info.name.into(),
|
||||
description: info.description.into(),
|
||||
author: info.author.into(),
|
||||
icon_url: info.icon_url.into(),
|
||||
local_url: None,
|
||||
version: info.version.into(),
|
||||
allow_js_eval: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,8 @@ pub struct PageHandler<T: DappFile> {
|
||||
pub safe_to_embed_on: Embeddable,
|
||||
/// Cache settings for this page.
|
||||
pub cache: PageCache,
|
||||
/// Allow JS unsafe-eval.
|
||||
pub allow_js_eval: bool,
|
||||
}
|
||||
|
||||
impl<T: DappFile> PageHandler<T> {
|
||||
@@ -93,7 +95,7 @@ impl<T: DappFile> PageHandler<T> {
|
||||
|
||||
headers.set(header::ContentType(file.content_type().to_owned()));
|
||||
|
||||
add_security_headers(&mut headers, self.safe_to_embed_on);
|
||||
add_security_headers(&mut headers, self.safe_to_embed_on, self.allow_js_eval);
|
||||
}
|
||||
|
||||
let initial_content = if file.content_type().to_owned() == mime::TEXT_HTML {
|
||||
|
||||
@@ -98,6 +98,7 @@ impl Dapp {
|
||||
file: self.get_file(path),
|
||||
cache: self.cache,
|
||||
safe_to_embed_on: self.embeddable_on.clone(),
|
||||
allow_js_eval: self.info.as_ref().and_then(|x| x.allow_js_eval).unwrap_or(false),
|
||||
}.into_response();
|
||||
|
||||
self.pool.spawn(reader).forget();
|
||||
|
||||
@@ -181,7 +181,7 @@ fn should_return_fetched_dapp_content() {
|
||||
assert_security_headers_for_embed(&response2.headers);
|
||||
assert_eq!(
|
||||
response2.body,
|
||||
r#"D2
|
||||
r#"EA
|
||||
{
|
||||
"id": "9c94e154dab8acf859b30ee80fc828fb1d38359d938751b65db71d460588d82a",
|
||||
"name": "Gavcoin",
|
||||
@@ -189,7 +189,8 @@ fn should_return_fetched_dapp_content() {
|
||||
"version": "1.0.0",
|
||||
"author": "",
|
||||
"iconUrl": "icon.png",
|
||||
"localUrl": null
|
||||
"localUrl": null,
|
||||
"allowJsEval": false
|
||||
}
|
||||
0
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ rustc_version = "0.1"
|
||||
parity-ui-dev = { path = "../../js", optional = true }
|
||||
parity-ui-old-dev = { path = "../../js-old", optional = true }
|
||||
# This is managed by the js/scripts/release.sh script on CI - keep it in a single line
|
||||
parity-ui-old-precompiled = { git = "https://github.com/js-dist-paritytech/parity-master-1-9-v1.git", optional = true }
|
||||
parity-ui-precompiled = { git = "https://github.com/js-dist-paritytech/parity-master-1-9-shell.git", optional = true }
|
||||
parity-ui-old-precompiled = { git = "https://github.com/js-dist-paritytech/parity-beta-1-9-v1.git", optional = true }
|
||||
parity-ui-precompiled = { git = "https://github.com/js-dist-paritytech/parity-beta-1-9-shell.git", optional = true }
|
||||
|
||||
[features]
|
||||
no-precompiled-js = ["parity-ui-dev", "parity-ui-old-dev"]
|
||||
|
||||
@@ -33,7 +33,7 @@ impl Factory {
|
||||
/// Create fresh instance of VM
|
||||
/// Might choose implementation depending on supplied gas.
|
||||
#[cfg(feature = "jit")]
|
||||
pub fn create(&self, gas: U256) -> Box<Vm> {
|
||||
pub fn create(&self, gas: &U256) -> Box<Vm> {
|
||||
match self.evm {
|
||||
VMType::Jit => {
|
||||
Box::new(super::jit::JitEvm::default())
|
||||
@@ -49,7 +49,7 @@ impl Factory {
|
||||
/// Create fresh instance of VM
|
||||
/// Might choose implementation depending on supplied gas.
|
||||
#[cfg(not(feature = "jit"))]
|
||||
pub fn create(&self, gas: U256) -> Box<Vm> {
|
||||
pub fn create(&self, gas: &U256) -> Box<Vm> {
|
||||
match self.evm {
|
||||
VMType::Interpreter => if Self::can_fit_in_usize(gas) {
|
||||
Box::new(super::interpreter::Interpreter::<usize>::new(self.evm_cache.clone()))
|
||||
@@ -68,8 +68,8 @@ impl Factory {
|
||||
}
|
||||
}
|
||||
|
||||
fn can_fit_in_usize(gas: U256) -> bool {
|
||||
gas == U256::from(gas.low_u64() as usize)
|
||||
fn can_fit_in_usize(gas: &U256) -> bool {
|
||||
gas == &U256::from(gas.low_u64() as usize)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ impl Default for Factory {
|
||||
|
||||
#[test]
|
||||
fn test_create_vm() {
|
||||
let _vm = Factory::default().create(U256::zero());
|
||||
let _vm = Factory::default().create(&U256::zero());
|
||||
}
|
||||
|
||||
/// Create tests by injecting different VM factories
|
||||
|
||||
@@ -914,8 +914,13 @@ mod tests {
|
||||
use rustc_hex::FromHex;
|
||||
use vmtype::VMType;
|
||||
use factory::Factory;
|
||||
use vm::{ActionParams, ActionValue};
|
||||
use vm::{Vm, ActionParams, ActionValue};
|
||||
use vm::tests::{FakeExt, test_finalize};
|
||||
use bigint::prelude::U256;
|
||||
|
||||
fn interpreter(gas: &U256) -> Box<Vm> {
|
||||
Factory::new(VMType::Interpreter, 1).create(gas)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_not_fail_on_tracing_mem() {
|
||||
@@ -932,7 +937,7 @@ mod tests {
|
||||
ext.tracing = true;
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = Factory::new(VMType::Interpreter, 1).create(params.gas);
|
||||
let mut vm = interpreter(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -954,7 +959,7 @@ mod tests {
|
||||
ext.tracing = true;
|
||||
|
||||
let err = {
|
||||
let mut vm = Factory::new(VMType::Interpreter, 1).create(params.gas);
|
||||
let mut vm = interpreter(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).err().unwrap()
|
||||
};
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ fn test_add(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -60,7 +60,7 @@ fn test_sha3(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -80,7 +80,7 @@ fn test_address(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -102,7 +102,7 @@ fn test_origin(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -124,7 +124,7 @@ fn test_sender(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -159,7 +159,7 @@ fn test_extcodecopy(factory: super::Factory) {
|
||||
ext.codes.insert(sender, Arc::new(sender_code));
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -179,7 +179,7 @@ fn test_log_empty(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -211,7 +211,7 @@ fn test_log_sender(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -236,7 +236,7 @@ fn test_blockhash(factory: super::Factory) {
|
||||
ext.blockhashes.insert(U256::zero(), blockhash.clone());
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -258,7 +258,7 @@ fn test_calldataload(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -279,7 +279,7 @@ fn test_author(factory: super::Factory) {
|
||||
ext.info.author = author;
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -299,7 +299,7 @@ fn test_timestamp(factory: super::Factory) {
|
||||
ext.info.timestamp = timestamp;
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -319,7 +319,7 @@ fn test_number(factory: super::Factory) {
|
||||
ext.info.number = number;
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -339,7 +339,7 @@ fn test_difficulty(factory: super::Factory) {
|
||||
ext.info.difficulty = difficulty;
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -359,7 +359,7 @@ fn test_gas_limit(factory: super::Factory) {
|
||||
ext.info.gas_limit = gas_limit;
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -377,7 +377,7 @@ fn test_mul(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -395,7 +395,7 @@ fn test_sub(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -413,7 +413,7 @@ fn test_div(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -431,7 +431,7 @@ fn test_div_zero(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -449,7 +449,7 @@ fn test_mod(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -468,7 +468,7 @@ fn test_smod(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -487,7 +487,7 @@ fn test_sdiv(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -506,7 +506,7 @@ fn test_exp(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -526,7 +526,7 @@ fn test_comparison(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -547,7 +547,7 @@ fn test_signed_comparison(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -568,7 +568,7 @@ fn test_bitops(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -591,7 +591,7 @@ fn test_addmod_mulmod(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -612,7 +612,7 @@ fn test_byte(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -631,7 +631,7 @@ fn test_signextend(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -651,7 +651,7 @@ fn test_badinstruction_int() {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let err = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap_err()
|
||||
};
|
||||
|
||||
@@ -671,7 +671,7 @@ fn test_pop(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -691,7 +691,7 @@ fn test_extops(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -714,7 +714,7 @@ fn test_jumps(factory: super::Factory) {
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -742,7 +742,7 @@ fn test_calls(factory: super::Factory) {
|
||||
};
|
||||
|
||||
let gas_left = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
@@ -781,7 +781,7 @@ fn test_create_in_staticcall(factory: super::Factory) {
|
||||
ext.is_static = true;
|
||||
|
||||
let err = {
|
||||
let mut vm = factory.create(params.gas);
|
||||
let mut vm = factory.create(¶ms.gas);
|
||||
test_finalize(vm.exec(params, &mut ext)).unwrap_err()
|
||||
};
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ memorydb = { path = "../../util/memorydb" }
|
||||
patricia-trie = { path = "../../util/patricia_trie" }
|
||||
ethcore-network = { path = "../../util/network" }
|
||||
ethcore-io = { path = "../../util/io" }
|
||||
evm = { path = "../evm" }
|
||||
heapsize = "0.4"
|
||||
vm = { path = "../vm" }
|
||||
rlp = { path = "../../util/rlp" }
|
||||
|
||||
@@ -60,7 +60,6 @@ extern crate ethcore_util as util;
|
||||
extern crate ethcore_bigint as bigint;
|
||||
extern crate ethcore_bytes as bytes;
|
||||
extern crate ethcore;
|
||||
extern crate evm;
|
||||
extern crate heapsize;
|
||||
extern crate futures;
|
||||
extern crate itertools;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
//! The request service is implemented using Futures. Higher level request handlers
|
||||
//! will take the raw data received here and extract meaningful results from it.
|
||||
|
||||
use std::cmp;
|
||||
use std::collections::HashMap;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
@@ -28,6 +29,7 @@ use futures::{Async, Poll, Future};
|
||||
use futures::sync::oneshot::{self, Sender, Receiver, Canceled};
|
||||
use network::PeerId;
|
||||
use parking_lot::{RwLock, Mutex};
|
||||
use rand;
|
||||
|
||||
use net::{
|
||||
self, Handler, PeerStatus, Status, Capabilities,
|
||||
@@ -90,7 +92,14 @@ impl Pending {
|
||||
match self.requests[idx].respond_local(cache) {
|
||||
Some(response) => {
|
||||
self.requests.supply_response_unchecked(&response);
|
||||
|
||||
// update header and back-references after each from-cache
|
||||
// response to ensure that the requests are left in a consistent
|
||||
// state and increase the likelihood of being able to answer
|
||||
// the next request from cache.
|
||||
self.update_header_refs(idx, &response);
|
||||
self.fill_unanswered();
|
||||
|
||||
self.responses.push(response);
|
||||
}
|
||||
None => break,
|
||||
@@ -382,7 +391,10 @@ impl OnDemand {
|
||||
true => None,
|
||||
})
|
||||
.filter_map(|pending| {
|
||||
for (peer_id, peer) in peers.iter() { // .shuffle?
|
||||
// the peer we dispatch to is chosen randomly
|
||||
let num_peers = peers.len();
|
||||
let rng = rand::random::<usize>() % cmp::max(num_peers, 1);
|
||||
for (peer_id, peer) in peers.iter().chain(peers.iter()).skip(rng).take(num_peers) {
|
||||
// TODO: see which requests can be answered by the cache?
|
||||
|
||||
if !peer.can_fulfill(&pending.required_capabilities) {
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
"ecip1010ContinueTransition": 5000000,
|
||||
"ecip1017EraRounds": 5000000,
|
||||
"eip161abcTransition": "0x7fffffffffffffff",
|
||||
"eip161dTransition": "0x7fffffffffffffff"
|
||||
"eip161dTransition": "0x7fffffffffffffff",
|
||||
"bombDefuseTransition": 5900000
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
74
ethcore/res/ethereum/kovan_wasm_test.json
Normal file
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"name": "Kovan (Test)",
|
||||
"dataDir": "kovan-test",
|
||||
"engine": {
|
||||
"authorityRound": {
|
||||
"params": {
|
||||
"stepDuration": "4",
|
||||
"blockReward": "0x4563918244F40000",
|
||||
"validators" : {
|
||||
"list": [
|
||||
"0x00D6Cc1BA9cf89BD2e58009741f4F7325BAdc0ED",
|
||||
"0x00427feae2419c15b89d1c21af10d1b6650a4d3d",
|
||||
"0x4Ed9B08e6354C70fE6F8CB0411b0d3246b424d6c",
|
||||
"0x0020ee4Be0e2027d76603cB751eE069519bA81A1",
|
||||
"0x0010f94b296a852aaac52ea6c5ac72e03afd032d",
|
||||
"0x007733a1FE69CF3f2CF989F81C7b4cAc1693387A",
|
||||
"0x00E6d2b931F55a3f1701c7389d592a7778897879",
|
||||
"0x00e4a10650e5a6D6001C38ff8E64F97016a1645c",
|
||||
"0x00a0a24b9f0e5ec7aa4c7389b8302fd0123194de"
|
||||
]
|
||||
},
|
||||
"validateScoreTransition": 1000000,
|
||||
"validateStepTransition": 1500000,
|
||||
"maximumUncleCountTransition": 5067000,
|
||||
"maximumUncleCount": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"params": {
|
||||
"gasLimitBoundDivisor": "0x400",
|
||||
"registrar" : "0xfAb104398BBefbd47752E7702D9fE23047E1Bca3",
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID" : "0x2A",
|
||||
"forkBlock": 4297256,
|
||||
"forkCanonHash": "0x0a66d93c2f727dca618fabaf70c39b37018c73d78b939d8b11efbbd09034778f",
|
||||
"validateReceiptsTransition" : 1000000,
|
||||
"eip155Transition": 1000000,
|
||||
"validateChainIdTransition": 1000000,
|
||||
"eip140Transition": 5067000,
|
||||
"eip211Transition": 5067000,
|
||||
"eip214Transition": 5067000,
|
||||
"eip658Transition": 5067000,
|
||||
"wasmActivationTransition": 10
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
"authorityRound": {
|
||||
"step": "0x0",
|
||||
"signature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
},
|
||||
"difficulty": "0x20000",
|
||||
"gasLimit": "0x5B8D80"
|
||||
},
|
||||
"accounts": {
|
||||
"0x0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||
"0x0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||
"0x0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||
"0x0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
|
||||
"0x0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": 5067000, "pricing": { "modexp": { "divisor": 20 } } } },
|
||||
"0x0000000000000000000000000000000000000006": { "builtin": { "name": "alt_bn128_add", "activate_at": 5067000, "pricing": { "linear": { "base": 500, "word": 0 } } } },
|
||||
"0x0000000000000000000000000000000000000007": { "builtin": { "name": "alt_bn128_mul", "activate_at": 5067000, "pricing": { "linear": { "base": 40000, "word": 0 } } } },
|
||||
"0x0000000000000000000000000000000000000008": { "builtin": { "name": "alt_bn128_pairing", "activate_at": 5067000, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } },
|
||||
"0x00521965e7bd230323c423d96c657db5b79d099f": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }
|
||||
},
|
||||
"nodes": [
|
||||
"enode://56abaf065581a5985b8c5f4f88bd202526482761ba10be9bfdcd14846dd01f652ec33fde0f8c0fd1db19b59a4c04465681fcef50e11380ca88d25996191c52de@40.71.221.215:30303",
|
||||
"enode://d07827483dc47b368eaf88454fb04b41b7452cf454e194e2bd4c14f98a3278fed5d819dbecd0d010407fc7688d941ee1e58d4f9c6354d3da3be92f55c17d7ce3@52.166.117.77:30303",
|
||||
"enode://8fa162563a8e5a05eef3e1cd5abc5828c71344f7277bb788a395cce4a0e30baf2b34b92fe0b2dbbba2313ee40236bae2aab3c9811941b9f5a7e8e90aaa27ecba@52.165.239.18:30303",
|
||||
"enode://7e2e7f00784f516939f94e22bdc6cf96153603ca2b5df1c7cc0f90a38e7a2f218ffb1c05b156835e8b49086d11fdd1b3e2965be16baa55204167aa9bf536a4d9@52.243.47.56:30303",
|
||||
"enode://0518a3d35d4a7b3e8c433e7ffd2355d84a1304ceb5ef349787b556197f0c87fad09daed760635b97d52179d645d3e6d16a37d2cc0a9945c2ddf585684beb39ac@40.68.248.100:30303"
|
||||
]
|
||||
}
|
||||
@@ -14,9 +14,9 @@
|
||||
"ecip1010PauseTransition": 1915000,
|
||||
"ecip1010ContinueTransition": 3415000,
|
||||
"ecip1017EraRounds": 2000000,
|
||||
|
||||
"eip161abcTransition": "0x7fffffffffffffff",
|
||||
"eip161dTransition": "0x7fffffffffffffff"
|
||||
"eip161dTransition": "0x7fffffffffffffff",
|
||||
"bombDefuseTransition": 2300000
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -31,7 +31,6 @@
|
||||
"forkBlock": "0x1b34d8",
|
||||
"forkCanonHash": "0xf376243aeff1f256d970714c3de9fd78fa4e63cf63e32a51fe1169e375d98145",
|
||||
"eip155Transition": 1915000,
|
||||
|
||||
"eip98Transition": "0x7fffffffffffff",
|
||||
"eip86Transition": "0x7fffffffffffff"
|
||||
},
|
||||
|
||||
@@ -52,8 +52,10 @@
|
||||
"gasLimit": "0x1000000"
|
||||
},
|
||||
"nodes": [
|
||||
"enode://20c9ad97c081d63397d7b685a412227a40e23c8bdc6688c6f37e97cfbc22d2b4d1db1510d8f61e6a8866ad7f0e17c02b14182d37ea7c3c8b9c2683aeb6b733a1@52.169.14.227:30303",
|
||||
"enode://6ce05930c72abc632c58e2e4324f7c7ea478cec0ed4fa2528982cf34483094e9cbc9216e7aa349691242576d552a2a56aaeae426c5303ded677ce455ba1acd9d@13.84.180.240:30303"
|
||||
"enode://6332792c4a00e3e4ee0926ed89e0d27ef985424d97b6a45bf0f23e51f0dcb5e66b875777506458aea7af6f9e4ffb69f43f3778ee73c81ed9d34c51c4b16b0b0f@52.232.243.152:30303",
|
||||
"enode://94c15d1b9e2fe7ce56e458b9a3b672ef11894ddedd0c6f247e0f1d3487f52b66208fb4aeb8179fce6e3a749ea93ed147c37976d67af557508d199d9594c35f09@192.81.208.223:30303",
|
||||
"enode://30b7ab30a01c124a6cceca36863ece12c4f5fa68e3ba9b0b51407ccc002eeed3b3102d20a88f1c1d3c3154e2449317b8ef95090e77b312d5cc39354f86d5d606@52.176.7.10:30303",
|
||||
"enode://865a63255b3bb68023b6bffd5095118fcc13e79dcf014fe4e47e065c350c7cc72af2e53eff895f11ba1bbb6a2b33271c1116ee870f266618eadfc2e78aa7349c@52.176.100.77:30303"
|
||||
],
|
||||
"accounts": {
|
||||
"0000000000000000000000000000000000000000": { "balance": "1" },
|
||||
|
||||
@@ -264,9 +264,9 @@ impl AccountProvider {
|
||||
Ok(Address::from(account.address).into())
|
||||
}
|
||||
|
||||
/// Import a new presale wallet.
|
||||
pub fn import_wallet(&self, json: &[u8], password: &str) -> Result<Address, Error> {
|
||||
let account = self.sstore.import_wallet(SecretVaultRef::Root, json, password)?;
|
||||
/// Import a new wallet.
|
||||
pub fn import_wallet(&self, json: &[u8], password: &str, gen_id: bool) -> Result<Address, Error> {
|
||||
let account = self.sstore.import_wallet(SecretVaultRef::Root, json, password, gen_id)?;
|
||||
if self.blacklisted_accounts.contains(&account.address) {
|
||||
self.sstore.remove_account(&account, password)?;
|
||||
return Err(SSError::InvalidAccount.into());
|
||||
|
||||
@@ -50,9 +50,9 @@ use encoded;
|
||||
use engines::{EthEngine, EpochTransition};
|
||||
use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError};
|
||||
use vm::{EnvInfo, LastHashes};
|
||||
use evm::{Factory as EvmFactory, Schedule};
|
||||
use evm::Schedule;
|
||||
use executive::{Executive, Executed, TransactOptions, contract_address};
|
||||
use factory::Factories;
|
||||
use factory::{Factories, VmFactory};
|
||||
use futures::{future, Future};
|
||||
use header::{BlockNumber, Header};
|
||||
use io::*;
|
||||
@@ -189,7 +189,7 @@ impl Client {
|
||||
|
||||
let trie_factory = TrieFactory::new(trie_spec);
|
||||
let factories = Factories {
|
||||
vm: EvmFactory::new(config.vm_type.clone(), config.jump_table_size),
|
||||
vm: VmFactory::new(config.vm_type.clone(), config.jump_table_size),
|
||||
trie: trie_factory,
|
||||
accountdb: Default::default(),
|
||||
};
|
||||
@@ -1910,7 +1910,7 @@ impl MiningBlockChainClient for Client {
|
||||
block
|
||||
}
|
||||
|
||||
fn vm_factory(&self) -> &EvmFactory {
|
||||
fn vm_factory(&self) -> &VmFactory {
|
||||
&self.factories.vm
|
||||
}
|
||||
|
||||
|
||||
@@ -20,12 +20,11 @@ use std::fmt;
|
||||
use std::sync::Arc;
|
||||
use bigint::prelude::U256;
|
||||
use bigint::hash::H256;
|
||||
use journaldb;
|
||||
use {trie, kvdb_memorydb, bytes};
|
||||
use {factory, journaldb, trie, kvdb_memorydb, bytes};
|
||||
use kvdb::{self, KeyValueDB};
|
||||
use {state, state_db, client, executive, trace, transaction, db, spec, pod_state};
|
||||
use factory::Factories;
|
||||
use evm::{self, VMType, FinalizationResult};
|
||||
use evm::{VMType, FinalizationResult};
|
||||
use vm::{self, ActionParams};
|
||||
|
||||
/// EVM test Error.
|
||||
@@ -120,7 +119,7 @@ impl<'a> EvmTestClient<'a> {
|
||||
|
||||
fn factories() -> Factories {
|
||||
Factories {
|
||||
vm: evm::Factory::new(VMType::Interpreter, 5 * 1024),
|
||||
vm: factory::VmFactory::new(VMType::Interpreter, 5 * 1024),
|
||||
trie: trie::TrieFactory::new(trie::TrieSpec::Secure),
|
||||
accountdb: Default::default(),
|
||||
}
|
||||
|
||||
@@ -47,7 +47,8 @@ use log_entry::LocalizedLogEntry;
|
||||
use receipt::{Receipt, LocalizedReceipt, TransactionOutcome};
|
||||
use blockchain::extras::BlockReceipts;
|
||||
use error::{ImportResult, Error as EthcoreError};
|
||||
use evm::{Factory as EvmFactory, VMType};
|
||||
use evm::VMType;
|
||||
use factory::VmFactory;
|
||||
use vm::Schedule;
|
||||
use miner::{Miner, MinerService, TransactionImportResult};
|
||||
use spec::Spec;
|
||||
@@ -98,7 +99,7 @@ pub struct TestBlockChainClient {
|
||||
/// Spec
|
||||
pub spec: Spec,
|
||||
/// VM Factory
|
||||
pub vm_factory: EvmFactory,
|
||||
pub vm_factory: VmFactory,
|
||||
/// Timestamp assigned to latest sealed block
|
||||
pub latest_block_timestamp: RwLock<u64>,
|
||||
/// Ancient block info.
|
||||
@@ -169,7 +170,7 @@ impl TestBlockChainClient {
|
||||
queue_size: AtomicUsize::new(0),
|
||||
miner: Arc::new(Miner::with_spec(&spec)),
|
||||
spec: spec,
|
||||
vm_factory: EvmFactory::new(VMType::Interpreter, 1024 * 1024),
|
||||
vm_factory: VmFactory::new(VMType::Interpreter, 1024 * 1024),
|
||||
latest_block_timestamp: RwLock::new(10_000_000),
|
||||
ancient_block: RwLock::new(None),
|
||||
first_block: RwLock::new(None),
|
||||
@@ -399,7 +400,7 @@ impl MiningBlockChainClient for TestBlockChainClient {
|
||||
block.reopen(&*self.spec.engine)
|
||||
}
|
||||
|
||||
fn vm_factory(&self) -> &EvmFactory {
|
||||
fn vm_factory(&self) -> &VmFactory {
|
||||
&self.vm_factory
|
||||
}
|
||||
|
||||
|
||||
@@ -21,9 +21,9 @@ use block::{OpenBlock, SealedBlock, ClosedBlock};
|
||||
use blockchain::TreeRoute;
|
||||
use encoded;
|
||||
use vm::LastHashes;
|
||||
use error::{ImportResult, CallError, Error as EthcoreError};
|
||||
use error::{TransactionImportResult, BlockImportError};
|
||||
use evm::{Factory as EvmFactory, Schedule};
|
||||
use error::{ImportResult, CallError, Error as EthcoreError, TransactionImportResult, BlockImportError};
|
||||
use evm::Schedule;
|
||||
use factory::VmFactory;
|
||||
use executive::Executed;
|
||||
use filter::Filter;
|
||||
use header::{BlockNumber};
|
||||
@@ -298,7 +298,7 @@ pub trait MiningBlockChainClient: BlockChainClient {
|
||||
fn reopen_block(&self, block: ClosedBlock) -> OpenBlock;
|
||||
|
||||
/// Returns EvmFactory.
|
||||
fn vm_factory(&self) -> &EvmFactory;
|
||||
fn vm_factory(&self) -> &VmFactory;
|
||||
|
||||
/// Broadcast a block proposal.
|
||||
fn broadcast_proposal_block(&self, block: SealedBlock);
|
||||
|
||||
@@ -44,8 +44,7 @@ use bigint::hash::{H256, H520};
|
||||
use semantic_version::SemanticVersion;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use unexpected::{Mismatch, OutOfBounds};
|
||||
use util::*;
|
||||
use bytes::Bytes;
|
||||
use util::Address;
|
||||
|
||||
mod finality;
|
||||
|
||||
@@ -291,9 +290,11 @@ struct EpochVerifier {
|
||||
|
||||
impl super::EpochVerifier<EthereumMachine> for EpochVerifier {
|
||||
fn verify_light(&self, header: &Header) -> Result<(), Error> {
|
||||
// Validate the timestamp
|
||||
verify_timestamp(&*self.step, header_step(header)?)?;
|
||||
// always check the seal since it's fast.
|
||||
// nothing heavier to do.
|
||||
verify_external(header, &self.subchain_validators, &*self.step, |_| {})
|
||||
verify_external(header, &self.subchain_validators)
|
||||
}
|
||||
|
||||
fn check_finality_proof(&self, proof: &[u8]) -> Option<Vec<H256>> {
|
||||
@@ -317,7 +318,7 @@ impl super::EpochVerifier<EthereumMachine> for EpochVerifier {
|
||||
//
|
||||
// `verify_external` checks that signature is correct and author == signer.
|
||||
if header.seal().len() != 2 { return None }
|
||||
otry!(verify_external(header, &self.subchain_validators, &*self.step, |_| {}).ok());
|
||||
otry!(verify_external(header, &self.subchain_validators).ok());
|
||||
|
||||
let newly_finalized = otry!(finality_checker.push_hash(header.hash(), header.author().clone()).ok());
|
||||
finalized.extend(newly_finalized);
|
||||
@@ -327,16 +328,6 @@ impl super::EpochVerifier<EthereumMachine> for EpochVerifier {
|
||||
}
|
||||
}
|
||||
|
||||
// Report misbehavior
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
enum Report {
|
||||
// Malicious behavior
|
||||
Malicious(Address, BlockNumber, Bytes),
|
||||
// benign misbehavior
|
||||
Benign(Address, BlockNumber),
|
||||
}
|
||||
|
||||
fn header_step(header: &Header) -> Result<usize, ::rlp::DecoderError> {
|
||||
UntrustedRlp::new(&header.seal().get(0).expect("was either checked with verify_block_basic or is genesis; has 2 fields; qed (Make sure the spec file has a correct genesis seal)")).as_val()
|
||||
}
|
||||
@@ -355,34 +346,35 @@ fn is_step_proposer(validators: &ValidatorSet, bh: &H256, step: usize, address:
|
||||
step_proposer(validators, bh, step) == *address
|
||||
}
|
||||
|
||||
fn verify_external<F: Fn(Report)>(header: &Header, validators: &ValidatorSet, step: &Step, report: F)
|
||||
-> Result<(), Error>
|
||||
{
|
||||
let header_step = header_step(header)?;
|
||||
|
||||
fn verify_timestamp(step: &Step, header_step: usize) -> Result<(), BlockError> {
|
||||
match step.check_future(header_step) {
|
||||
Err(None) => {
|
||||
trace!(target: "engine", "verify_block_external: block from the future");
|
||||
report(Report::Benign(*header.author(), header.number()));
|
||||
return Err(BlockError::InvalidSeal.into())
|
||||
trace!(target: "engine", "verify_timestamp: block from the future");
|
||||
Err(BlockError::InvalidSeal.into())
|
||||
},
|
||||
Err(Some(oob)) => {
|
||||
trace!(target: "engine", "verify_block_external: block too early");
|
||||
return Err(BlockError::TemporarilyInvalid(oob).into())
|
||||
// NOTE This error might be returned only in early stage of verification (Stage 1).
|
||||
// Returning it further won't recover the sync process.
|
||||
trace!(target: "engine", "verify_timestamp: block too early");
|
||||
Err(BlockError::TemporarilyInvalid(oob).into())
|
||||
},
|
||||
Ok(_) => {
|
||||
let proposer_signature = header_signature(header)?;
|
||||
let correct_proposer = validators.get(header.parent_hash(), header_step);
|
||||
let is_invalid_proposer = *header.author() != correct_proposer ||
|
||||
!verify_address(&correct_proposer, &proposer_signature, &header.bare_hash())?;
|
||||
Ok(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
if is_invalid_proposer {
|
||||
trace!(target: "engine", "verify_block_external: bad proposer for step: {}", header_step);
|
||||
Err(EngineError::NotProposer(Mismatch { expected: correct_proposer, found: header.author().clone() }))?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
fn verify_external(header: &Header, validators: &ValidatorSet) -> Result<(), Error> {
|
||||
let header_step = header_step(header)?;
|
||||
|
||||
let proposer_signature = header_signature(header)?;
|
||||
let correct_proposer = validators.get(header.parent_hash(), header_step);
|
||||
let is_invalid_proposer = *header.author() != correct_proposer ||
|
||||
!verify_address(&correct_proposer, &proposer_signature, &header.bare_hash())?;
|
||||
|
||||
if is_invalid_proposer {
|
||||
trace!(target: "engine", "verify_block_external: bad proposer for step: {}", header_step);
|
||||
Err(EngineError::NotProposer(Mismatch { expected: correct_proposer, found: header.author().clone() }))?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,26 +647,38 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
/// Check the number of seal fields.
|
||||
fn verify_block_basic(&self, header: &Header) -> Result<(), Error> {
|
||||
if header.number() >= self.validate_score_transition && *header.difficulty() >= U256::from(U128::max_value()) {
|
||||
Err(From::from(BlockError::DifficultyOutOfBounds(
|
||||
return Err(From::from(BlockError::DifficultyOutOfBounds(
|
||||
OutOfBounds { min: None, max: Some(U256::from(U128::max_value())), found: *header.difficulty() }
|
||||
)))
|
||||
} else {
|
||||
Ok(())
|
||||
)));
|
||||
}
|
||||
|
||||
// TODO [ToDr] Should this go from epoch manager?
|
||||
// If yes then probably benign reporting needs to be moved further in the verification.
|
||||
let set_number = header.number();
|
||||
|
||||
match verify_timestamp(&*self.step, header_step(header)?) {
|
||||
Err(BlockError::InvalidSeal) => {
|
||||
self.validators.report_benign(header.author(), set_number, header.number());
|
||||
Err(BlockError::InvalidSeal.into())
|
||||
}
|
||||
Err(e) => Err(e.into()),
|
||||
Ok(()) => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Do the step and gas limit validation.
|
||||
fn verify_block_family(&self, header: &Header, parent: &Header) -> Result<(), Error> {
|
||||
let step = header_step(header)?;
|
||||
|
||||
let parent_step = header_step(parent)?;
|
||||
// TODO [ToDr] Should this go from epoch manager?
|
||||
let set_number = header.number();
|
||||
|
||||
// Ensure header is from the step after parent.
|
||||
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(), header.number(), header.number(), Default::default());
|
||||
self.validators.report_malicious(header.author(), set_number, header.number(), Default::default());
|
||||
Err(EngineError::DoubleVote(header.author().clone()))?;
|
||||
}
|
||||
|
||||
@@ -687,7 +691,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
let skipped_primary = step_proposer(&*self.validators, &parent.hash(), s);
|
||||
// Do not report this signer.
|
||||
if skipped_primary != me {
|
||||
self.validators.report_benign(&skipped_primary, header.number(), header.number());
|
||||
self.validators.report_benign(&skipped_primary, set_number, header.number());
|
||||
}
|
||||
// Stop reporting once validators start repeating.
|
||||
if !reported.insert(skipped_primary) { break; }
|
||||
@@ -702,9 +706,8 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
// fetch correct validator set for current epoch, taking into account
|
||||
// finality of previous transitions.
|
||||
let active_set;
|
||||
|
||||
let (validators, set_number) = if self.immediate_transitions {
|
||||
(&*self.validators, header.number())
|
||||
let validators = if self.immediate_transitions {
|
||||
&*self.validators
|
||||
} else {
|
||||
// get correct validator set for epoch.
|
||||
let client = match self.client.read().as_ref().and_then(|weak| weak.upgrade()) {
|
||||
@@ -722,21 +725,12 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
}
|
||||
|
||||
active_set = epoch_manager.validators().clone();
|
||||
(&active_set as &_, epoch_manager.epoch_transition_number)
|
||||
};
|
||||
|
||||
// always report with "self.validators" so that the report actually gets
|
||||
// to the contract.
|
||||
let report = |report| match report {
|
||||
Report::Benign(address, block_number) =>
|
||||
self.validators.report_benign(&address, set_number, block_number),
|
||||
Report::Malicious(address, block_number, proof) =>
|
||||
self.validators.report_malicious(&address, set_number, block_number, proof),
|
||||
&active_set as &_
|
||||
};
|
||||
|
||||
// verify signature against fixed list, but reports should go to the
|
||||
// contract itself.
|
||||
verify_external(header, validators, &*self.step, report)
|
||||
verify_external(header, validators)
|
||||
}
|
||||
|
||||
fn genesis_epoch_data(&self, header: &Header, call: &Call) -> Result<Vec<u8>, String> {
|
||||
@@ -1059,8 +1053,7 @@ mod tests {
|
||||
assert!(engine.verify_block_family(&header, &parent_header).is_ok());
|
||||
assert!(engine.verify_block_external(&header).is_ok());
|
||||
header.set_seal(vec![encode(&5usize).into_vec(), encode(&(&*signature as &[u8])).into_vec()]);
|
||||
assert!(engine.verify_block_family(&header, &parent_header).is_ok());
|
||||
assert!(engine.verify_block_external(&header).is_err());
|
||||
assert!(engine.verify_block_basic(&header).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1200,3 +1193,4 @@ mod tests {
|
||||
AuthorityRound::new(params, machine).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -390,11 +390,6 @@ pub trait EthEngine: Engine<::machine::EthereumMachine> {
|
||||
self.machine().verify_transaction_basic(t, header)
|
||||
}
|
||||
|
||||
/// If this machine supports wasm.
|
||||
fn supports_wasm(&self) -> bool {
|
||||
self.machine().supports_wasm()
|
||||
}
|
||||
|
||||
/// Additional information.
|
||||
fn additional_params(&self) -> HashMap<String, String> {
|
||||
self.machine().additional_params()
|
||||
|
||||
@@ -192,7 +192,7 @@ mod tests {
|
||||
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).
|
||||
assert!(client.engine().verify_block_external(&header).is_err());
|
||||
assert!(client.engine().verify_block_basic(&header).is_err());
|
||||
// Seal a block.
|
||||
client.engine().step();
|
||||
assert_eq!(client.chain_info().best_block_number, 1);
|
||||
|
||||
@@ -141,6 +141,9 @@ pub fn new_constantinople_test_machine() -> EthereumMachine { load_machine(inclu
|
||||
/// Create a new Musicoin-MCIP3-era spec.
|
||||
pub fn new_mcip3_test_machine() -> EthereumMachine { load_machine(include_bytes!("../../res/ethereum/mcip3_test.json")) }
|
||||
|
||||
/// Create new Kovan spec with wasm activated at certain block
|
||||
pub fn new_kovan_wasm_test_machine() -> EthereumMachine { load_machine(include_bytes!("../../res/ethereum/kovan_wasm_test.json")) }
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use bigint::prelude::U256;
|
||||
|
||||
@@ -24,11 +24,12 @@ use util::*;
|
||||
use bytes::{Bytes, BytesRef};
|
||||
use state::{Backend as StateBackend, State, Substate, CleanupMode};
|
||||
use machine::EthereumMachine as Machine;
|
||||
use vm::EnvInfo;
|
||||
use error::ExecutionError;
|
||||
use evm::{CallType, Factory, Finalize, FinalizationResult};
|
||||
use vm::{self, Ext, CreateContractAddress, ReturnData, CleanDustMode, ActionParams, ActionValue};
|
||||
use wasm;
|
||||
use evm::{CallType, Finalize, FinalizationResult};
|
||||
use vm::{
|
||||
self, Ext, EnvInfo, CreateContractAddress, ReturnData, CleanDustMode, ActionParams,
|
||||
ActionValue, Schedule,
|
||||
};
|
||||
use externalities::*;
|
||||
use trace::{self, Tracer, VMTracer};
|
||||
use transaction::{Action, SignedTransaction};
|
||||
@@ -40,8 +41,6 @@ pub use executed::{Executed, ExecutionResult};
|
||||
/// Maybe something like here: `https://github.com/ethereum/libethereum/blob/4db169b8504f2b87f7d5a481819cfb959fc65f6c/libethereum/ExtVM.cpp`
|
||||
const STACK_SIZE_PER_DEPTH: usize = 24*1024;
|
||||
|
||||
const WASM_MAGIC_NUMBER: &'static [u8; 4] = b"\0asm";
|
||||
|
||||
/// Returns new address created from address, nonce, and code hash
|
||||
pub fn contract_address(address_scheme: CreateContractAddress, sender: &Address, nonce: &U256, code: &[u8]) -> (Address, Option<H256>) {
|
||||
use rlp::RlpStream;
|
||||
@@ -154,18 +153,6 @@ impl TransactOptions<trace::NoopTracer, trace::NoopVMTracer> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn executor(machine: &Machine, vm_factory: &Factory, params: &ActionParams) -> Box<vm::Vm> {
|
||||
if machine.supports_wasm() && params.code.as_ref().map_or(false, |code| code.len() > 4 && &code[0..4] == WASM_MAGIC_NUMBER) {
|
||||
Box::new(
|
||||
wasm::WasmInterpreter::new()
|
||||
// prefer to fail fast
|
||||
.expect("Failed to create wasm runtime")
|
||||
)
|
||||
} else {
|
||||
vm_factory.create(params.gas)
|
||||
}
|
||||
}
|
||||
|
||||
/// Transaction executor.
|
||||
pub struct Executive<'a, B: 'a + StateBackend> {
|
||||
state: &'a mut State<B>,
|
||||
@@ -340,6 +327,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
||||
|
||||
fn exec_vm<T, V>(
|
||||
&mut self,
|
||||
schedule: Schedule,
|
||||
params: ActionParams,
|
||||
unconfirmed_substate: &mut Substate,
|
||||
output_policy: OutputPolicy,
|
||||
@@ -355,19 +343,20 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
||||
let vm_factory = self.state.vm_factory();
|
||||
let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call);
|
||||
trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call);
|
||||
return executor(self.machine, &vm_factory, ¶ms).exec(params, &mut ext).finalize(ext);
|
||||
let mut vm = vm_factory.create(¶ms, &schedule);
|
||||
return vm.exec(params, &mut ext).finalize(ext);
|
||||
}
|
||||
|
||||
// Start in new thread to reset stack
|
||||
// TODO [todr] No thread builder yet, so we need to reset once for a while
|
||||
// https://github.com/aturon/crossbeam/issues/16
|
||||
crossbeam::scope(|scope| {
|
||||
let machine = self.machine;
|
||||
let vm_factory = self.state.vm_factory();
|
||||
let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call);
|
||||
|
||||
scope.spawn(move || {
|
||||
executor(machine, &vm_factory, ¶ms).exec(params, &mut ext).finalize(ext)
|
||||
let mut vm = vm_factory.create(¶ms, &schedule);
|
||||
vm.exec(params, &mut ext).finalize(ext)
|
||||
})
|
||||
}).join()
|
||||
}
|
||||
@@ -477,7 +466,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
||||
let mut subvmtracer = vm_tracer.prepare_subtrace(params.code.as_ref().expect("scope is conditional on params.code.is_some(); qed"));
|
||||
|
||||
let res = {
|
||||
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()), &mut subtracer, &mut subvmtracer)
|
||||
self.exec_vm(schedule, params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()), &mut subtracer, &mut subvmtracer)
|
||||
};
|
||||
|
||||
vm_tracer.done_subtrace(subvmtracer);
|
||||
@@ -568,9 +557,14 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
||||
|
||||
let mut subvmtracer = vm_tracer.prepare_subtrace(params.code.as_ref().expect("two ways into create (Externalities::create and Executive::transact_with_tracer); both place `Some(...)` `code` in `params`; qed"));
|
||||
|
||||
let res = {
|
||||
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(output.as_mut().or(trace_output.as_mut())), &mut subtracer, &mut subvmtracer)
|
||||
};
|
||||
let res = self.exec_vm(
|
||||
schedule,
|
||||
params,
|
||||
&mut unconfirmed_substate,
|
||||
OutputPolicy::InitContract(output.as_mut().or(trace_output.as_mut())),
|
||||
&mut subtracer,
|
||||
&mut subvmtracer
|
||||
);
|
||||
|
||||
vm_tracer.done_subtrace(subvmtracer);
|
||||
|
||||
@@ -1489,8 +1483,6 @@ mod tests {
|
||||
params.gas = U256::from(20025);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.value = ActionValue::Transfer(U256::zero());
|
||||
let mut state = get_temp_state_with_factory(factory);
|
||||
state.add_balance(&sender, &U256::from_str("152d02c7e14af68000000").unwrap(), CleanupMode::NoEmpty).unwrap();
|
||||
let info = EnvInfo::default();
|
||||
let machine = ::ethereum::new_byzantium_test_machine();
|
||||
let mut substate = Substate::new();
|
||||
@@ -1505,4 +1497,60 @@ mod tests {
|
||||
assert_eq!(output[..], returns[..]);
|
||||
assert_eq!(state.storage_at(&contract_address, &H256::from(&U256::zero())).unwrap(), H256::from(&U256::from(0)));
|
||||
}
|
||||
|
||||
fn wasm_sample_code() -> Arc<Vec<u8>> {
|
||||
Arc::new(
|
||||
"0061736d01000000010d0360027f7f0060017f0060000002270303656e7603726574000003656e760673656e646572000103656e76066d656d6f727902010110030201020404017000000501000708010463616c6c00020901000ac10101be0102057f017e4100410028020441c0006b22043602042004412c6a41106a220041003602002004412c6a41086a22014200370200200441186a41106a22024100360200200441186a41086a220342003703002004420037022c2004410036021c20044100360218200441186a1001200020022802002202360200200120032903002205370200200441106a2002360200200441086a200537030020042004290318220537022c200420053703002004411410004100200441c0006a3602040b0b0a010041040b0410c00000"
|
||||
.from_hex()
|
||||
.unwrap()
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wasm_activated_test() {
|
||||
let contract_address = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap();
|
||||
let sender = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||
|
||||
let mut state = get_temp_state();
|
||||
state.add_balance(&sender, &U256::from(10000000000u64), CleanupMode::NoEmpty).unwrap();
|
||||
state.commit().unwrap();
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.origin = sender.clone();
|
||||
params.sender = sender.clone();
|
||||
params.address = contract_address.clone();
|
||||
params.gas = U256::from(20025);
|
||||
params.code = Some(wasm_sample_code());
|
||||
|
||||
let mut info = EnvInfo::default();
|
||||
|
||||
// 100 > 10
|
||||
info.number = 100;
|
||||
|
||||
// Network with wasm activated at block 10
|
||||
let machine = ::ethereum::new_kovan_wasm_test_machine();
|
||||
|
||||
let mut output = [0u8; 20];
|
||||
let FinalizationResult { gas_left: result, .. } = {
|
||||
let mut ex = Executive::new(&mut state, &info, &machine);
|
||||
ex.call(params.clone(), &mut Substate::new(), BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap()
|
||||
};
|
||||
|
||||
assert_eq!(result, U256::from(18433));
|
||||
// Transaction successfully returned sender
|
||||
assert_eq!(output[..], sender[..]);
|
||||
|
||||
// 1 < 10
|
||||
info.number = 1;
|
||||
|
||||
let mut output = [0u8; 20];
|
||||
let FinalizationResult { gas_left: result, .. } = {
|
||||
let mut ex = Executive::new(&mut state, &info, &machine);
|
||||
ex.call(params, &mut Substate::new(), BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap()
|
||||
};
|
||||
|
||||
assert_eq!(result, U256::from(20025));
|
||||
// Since transaction errored due to wasm was not activated, result is just empty
|
||||
assert_eq!(output[..], [0u8; 20][..]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,44 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use trie::TrieFactory;
|
||||
use evm::Factory as EvmFactory;
|
||||
use account_db::Factory as AccountFactory;
|
||||
use evm::{Factory as EvmFactory, VMType};
|
||||
use vm::{Vm, ActionParams, Schedule};
|
||||
use wasm::WasmInterpreter;
|
||||
|
||||
const WASM_MAGIC_NUMBER: &'static [u8; 4] = b"\0asm";
|
||||
|
||||
/// Virtual machine factory
|
||||
#[derive(Default, Clone)]
|
||||
pub struct VmFactory {
|
||||
evm: EvmFactory,
|
||||
}
|
||||
|
||||
impl VmFactory {
|
||||
pub fn create(&self, params: &ActionParams, schedule: &Schedule) -> Box<Vm> {
|
||||
if schedule.wasm.is_some() && params.code.as_ref().map_or(false, |code| code.len() > 4 && &code[0..4] == WASM_MAGIC_NUMBER) {
|
||||
Box::new(WasmInterpreter)
|
||||
} else {
|
||||
self.evm.create(¶ms.gas)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(evm: VMType, cache_size: usize) -> Self {
|
||||
VmFactory { evm: EvmFactory::new(evm, cache_size) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EvmFactory> for VmFactory {
|
||||
fn from(evm: EvmFactory) -> Self {
|
||||
VmFactory { evm: evm }
|
||||
}
|
||||
}
|
||||
|
||||
/// Collection of factories.
|
||||
#[derive(Default, Clone)]
|
||||
pub struct Factories {
|
||||
/// factory for evm.
|
||||
pub vm: EvmFactory,
|
||||
pub vm: VmFactory,
|
||||
/// factory for tries.
|
||||
pub trie: TrieFactory,
|
||||
/// factory for account databases.
|
||||
|
||||
@@ -259,7 +259,7 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
|
||||
&mut tracer,
|
||||
&mut vm_tracer,
|
||||
));
|
||||
let mut evm = vm_factory.create(params.gas);
|
||||
let mut evm = vm_factory.create(¶ms, &machine.schedule(0u64.into()));
|
||||
let res = evm.exec(params, &mut ex);
|
||||
// a return in finalize will not alter callcreates
|
||||
let callcreates = ex.callcreates.clone();
|
||||
|
||||
@@ -377,11 +377,6 @@ impl EthereumMachine {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// If this machine supports wasm.
|
||||
pub fn supports_wasm(&self) -> bool {
|
||||
self.params().wasm
|
||||
}
|
||||
|
||||
/// Additional params.
|
||||
pub fn additional_params(&self) -> HashMap<String, String> {
|
||||
hash_map![
|
||||
|
||||
@@ -110,8 +110,8 @@ pub struct CommonParams {
|
||||
pub nonce_cap_increment: u64,
|
||||
/// Enable dust cleanup for contracts.
|
||||
pub remove_dust_contracts: bool,
|
||||
/// Wasm support
|
||||
pub wasm: bool,
|
||||
/// Wasm activation blocknumber, if any disabled initially.
|
||||
pub wasm_activation_transition: BlockNumber,
|
||||
/// Gas limit bound divisor (how much gas limit can change per block)
|
||||
pub gas_limit_bound_divisor: U256,
|
||||
/// Registrar contract address.
|
||||
@@ -147,6 +147,9 @@ impl CommonParams {
|
||||
false => ::vm::CleanDustMode::BasicOnly,
|
||||
};
|
||||
}
|
||||
if block_number >= self.wasm_activation_transition {
|
||||
schedule.wasm = Some(Default::default());
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether these params contain any bug-fix hard forks.
|
||||
@@ -221,12 +224,15 @@ impl From<ethjson::spec::Params> for CommonParams {
|
||||
),
|
||||
nonce_cap_increment: p.nonce_cap_increment.map_or(64, Into::into),
|
||||
remove_dust_contracts: p.remove_dust_contracts.unwrap_or(false),
|
||||
wasm: p.wasm.unwrap_or(false),
|
||||
gas_limit_bound_divisor: p.gas_limit_bound_divisor.into(),
|
||||
registrar: p.registrar.map_or_else(Address::new, Into::into),
|
||||
node_permission_contract: p.node_permission_contract.map(Into::into),
|
||||
max_code_size: p.max_code_size.map_or(u64::max_value(), Into::into),
|
||||
transaction_permission_contract: p.transaction_permission_contract.map(Into::into),
|
||||
wasm_activation_transition: p.wasm_activation_transition.map_or(
|
||||
BlockNumber::max_value(),
|
||||
Into::into
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ use executed::{Executed, ExecutionError};
|
||||
use types::state_diff::StateDiff;
|
||||
use transaction::SignedTransaction;
|
||||
use state_db::StateDB;
|
||||
use evm::{Factory as EvmFactory};
|
||||
use factory::VmFactory;
|
||||
|
||||
use bigint::prelude::U256;
|
||||
use bigint::hash::H256;
|
||||
@@ -376,7 +376,7 @@ impl<B: Backend> State<B> {
|
||||
}
|
||||
|
||||
/// Get a VM factory that can execute on this state.
|
||||
pub fn vm_factory(&self) -> EvmFactory {
|
||||
pub fn vm_factory(&self) -> VmFactory {
|
||||
self.factories.vm.clone()
|
||||
}
|
||||
|
||||
@@ -1406,7 +1406,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_not_trace_delegatecall() {
|
||||
fn should_trace_delegatecall_properly() {
|
||||
init_log();
|
||||
|
||||
let mut state = get_temp_state();
|
||||
@@ -1426,7 +1426,7 @@ mod tests {
|
||||
}.sign(&secret(), None);
|
||||
|
||||
state.init_code(&0xa.into(), FromHex::from_hex("6000600060006000600b618000f4").unwrap()).unwrap();
|
||||
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()).unwrap();
|
||||
state.init_code(&0xb.into(), FromHex::from_hex("60056000526001601ff3").unwrap()).unwrap();
|
||||
let result = state.apply(&info, &machine, &t, true).unwrap();
|
||||
|
||||
let expected_trace = vec![FlatTrace {
|
||||
@@ -1441,23 +1441,23 @@ mod tests {
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: U256::from(721), // in post-eip150
|
||||
gas_used: U256::from(736), // in post-eip150
|
||||
output: vec![]
|
||||
}),
|
||||
}, FlatTrace {
|
||||
trace_address: vec![0].into_iter().collect(),
|
||||
subtraces: 0,
|
||||
action: trace::Action::Call(trace::Call {
|
||||
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
|
||||
to: 0xa.into(),
|
||||
from: 0xa.into(),
|
||||
to: 0xb.into(),
|
||||
value: 0.into(),
|
||||
gas: 32768.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::DelegateCall,
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: 3.into(),
|
||||
output: vec![],
|
||||
gas_used: 18.into(),
|
||||
output: vec![5],
|
||||
}),
|
||||
}];
|
||||
|
||||
|
||||
@@ -275,7 +275,7 @@ pub fn get_temp_state() -> State<::state_db::StateDB> {
|
||||
pub fn get_temp_state_with_factory(factory: EvmFactory) -> State<::state_db::StateDB> {
|
||||
let journal_db = get_temp_state_db();
|
||||
let mut factories = Factories::default();
|
||||
factories.vm = factory;
|
||||
factories.vm = factory.into();
|
||||
State::new(journal_db, U256::from(0), factories)
|
||||
}
|
||||
|
||||
|
||||
@@ -74,13 +74,23 @@ pub struct Call {
|
||||
|
||||
impl From<ActionParams> for Call {
|
||||
fn from(p: ActionParams) -> Self {
|
||||
Call {
|
||||
from: p.sender,
|
||||
to: p.address,
|
||||
value: p.value.value(),
|
||||
gas: p.gas,
|
||||
input: p.data.unwrap_or_else(Vec::new),
|
||||
call_type: p.call_type,
|
||||
match p.call_type {
|
||||
CallType::DelegateCall => Call {
|
||||
from: p.address,
|
||||
to: p.code_address,
|
||||
value: p.value.value(),
|
||||
gas: p.gas,
|
||||
input: p.data.unwrap_or_else(Vec::new),
|
||||
call_type: p.call_type,
|
||||
},
|
||||
_ => Call {
|
||||
from: p.sender,
|
||||
to: p.address,
|
||||
value: p.value.value(),
|
||||
gas: p.gas,
|
||||
input: p.data.unwrap_or_else(Vec::new),
|
||||
call_type: p.call_type,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ pub mod tests;
|
||||
pub use action_params::{ActionParams, ActionValue, ParamsType};
|
||||
pub use call_type::CallType;
|
||||
pub use env_info::{EnvInfo, LastHashes};
|
||||
pub use schedule::{Schedule, CleanDustMode};
|
||||
pub use schedule::{Schedule, CleanDustMode, WasmCosts};
|
||||
pub use ext::{Ext, MessageCallResult, ContractCreateResult, CreateContractAddress};
|
||||
pub use return_data::{ReturnData, GasLeft};
|
||||
pub use error::{Error, Result};
|
||||
|
||||
@@ -113,8 +113,8 @@ pub struct Schedule {
|
||||
pub kill_dust: CleanDustMode,
|
||||
/// Enable EIP-86 rules
|
||||
pub eip86: bool,
|
||||
/// Wasm extra schedule settings
|
||||
pub wasm: WasmCosts,
|
||||
/// Wasm extra schedule settings, if wasm activated
|
||||
pub wasm: Option<WasmCosts>,
|
||||
}
|
||||
|
||||
/// Wasm cost table
|
||||
@@ -127,18 +127,19 @@ pub struct WasmCosts {
|
||||
pub mul: u32,
|
||||
/// Memory (load/store) operations multiplier.
|
||||
pub mem: u32,
|
||||
/// Memory copy operation, per byte.
|
||||
pub mem_copy: u32,
|
||||
/// Memory move operation, per byte.
|
||||
pub mem_move: u32,
|
||||
/// Memory set operation, per byte.
|
||||
pub mem_set: u32,
|
||||
/// Static region charge, per byte.
|
||||
pub static_region: u32,
|
||||
/// General static query of U256 value from env-info
|
||||
pub static_u256: u32,
|
||||
/// General static query of Address value from env-info
|
||||
pub static_address: u32,
|
||||
/// Memory stipend. Amount of free memory (in 64kb pages) each contract can use for stack.
|
||||
pub initial_mem: u32,
|
||||
/// Grow memory cost, per page (64kb)
|
||||
pub grow_mem: u32,
|
||||
/// Cost of wasm opcode is calculated as TABLE_ENTRY_COST * `opcodes_mul` / `opcodes_div`
|
||||
pub opcodes_mul: u32,
|
||||
/// Cost of wasm opcode is calculated as TABLE_ENTRY_COST * `opcodes_mul` / `opcodes_div`
|
||||
pub opcodes_div: u32,
|
||||
|
||||
}
|
||||
|
||||
impl Default for WasmCosts {
|
||||
@@ -148,12 +149,12 @@ impl Default for WasmCosts {
|
||||
div: 16,
|
||||
mul: 4,
|
||||
mem: 2,
|
||||
mem_copy: 1,
|
||||
mem_move: 1,
|
||||
mem_set: 1,
|
||||
static_region: 1,
|
||||
static_u256: 64,
|
||||
static_address: 40,
|
||||
initial_mem: 4096,
|
||||
grow_mem: 8192,
|
||||
opcodes_mul: 3,
|
||||
opcodes_div: 8,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -230,7 +231,7 @@ impl Schedule {
|
||||
have_static_call: false,
|
||||
kill_dust: CleanDustMode::Off,
|
||||
eip86: false,
|
||||
wasm: Default::default(),
|
||||
wasm: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,9 +294,17 @@ impl Schedule {
|
||||
have_static_call: false,
|
||||
kill_dust: CleanDustMode::Off,
|
||||
eip86: false,
|
||||
wasm: Default::default(),
|
||||
wasm: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns wasm schedule
|
||||
///
|
||||
/// May panic if there is no wasm schedule
|
||||
pub fn wasm(&self) -> &WasmCosts {
|
||||
// *** Prefer PANIC here instead of silently breaking consensus! ***
|
||||
self.wasm.as_ref().expect("Wasm schedule expected to exist while checking wasm contract. Misconfigured client?")
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Schedule {
|
||||
|
||||
@@ -78,15 +78,23 @@ pub fn test_finalize(res: Result<GasLeft>) -> Result<U256> {
|
||||
}
|
||||
|
||||
impl FakeExt {
|
||||
/// New fake externalities
|
||||
pub fn new() -> Self {
|
||||
FakeExt::default()
|
||||
}
|
||||
|
||||
/// New fake externalities with byzantium schedule rules
|
||||
pub fn new_byzantium() -> Self {
|
||||
let mut ext = FakeExt::default();
|
||||
ext.schedule = Schedule::new_byzantium();
|
||||
ext
|
||||
}
|
||||
|
||||
/// Alter fake externalities to allow wasm
|
||||
pub fn with_wasm(mut self) -> Self {
|
||||
self.schedule.wasm = Some(Default::default());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Ext for FakeExt {
|
||||
|
||||
@@ -8,7 +8,9 @@ byteorder = "1.0"
|
||||
ethcore-util = { path = "../../util" }
|
||||
ethcore-bigint = { path = "../../util/bigint" }
|
||||
log = "0.3"
|
||||
parity-wasm = "0.15"
|
||||
parity-wasm = "0.23"
|
||||
libc = "0.2"
|
||||
wasm-utils = { git = "https://github.com/paritytech/wasm-utils" }
|
||||
vm = { path = "../vm" }
|
||||
ethcore-logger = { path = "../../logger" }
|
||||
wasmi = { git = "https://github.com/pepyakin/wasmi" }
|
||||
@@ -16,7 +16,7 @@ fn load_code<P: AsRef<path::Path>>(p: P) -> io::Result<Vec<u8>> {
|
||||
}
|
||||
|
||||
fn wasm_interpreter() -> WasmInterpreter {
|
||||
WasmInterpreter::new().expect("wasm interpreter to create without errors")
|
||||
WasmInterpreter
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -14,178 +14,279 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Wasm env module bindings
|
||||
//! Env module glue for wasmi interpreter
|
||||
|
||||
use parity_wasm::elements::ValueType::*;
|
||||
use parity_wasm::interpreter::{self, UserFunctionDescriptor};
|
||||
use parity_wasm::interpreter::UserFunctionDescriptor::*;
|
||||
use super::runtime::{Runtime, UserTrap};
|
||||
use std::cell::RefCell;
|
||||
use wasmi::{
|
||||
self, Signature, Error, FuncRef, FuncInstance, MemoryDescriptor,
|
||||
MemoryRef, MemoryInstance,
|
||||
};
|
||||
|
||||
pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
|
||||
Static(
|
||||
"_storage_read",
|
||||
&[I32; 2],
|
||||
/// Internal ids all functions runtime supports. This is just a glue for wasmi interpreter
|
||||
/// that lacks high-level api and later will be factored out
|
||||
pub mod ids {
|
||||
pub const STORAGE_WRITE_FUNC: usize = 0;
|
||||
pub const STORAGE_READ_FUNC: usize = 10;
|
||||
pub const RET_FUNC: usize = 20;
|
||||
pub const GAS_FUNC: usize = 30;
|
||||
pub const FETCH_INPUT_FUNC: usize = 40;
|
||||
pub const INPUT_LENGTH_FUNC: usize = 50;
|
||||
pub const CCALL_FUNC: usize = 60;
|
||||
pub const SCALL_FUNC: usize = 70;
|
||||
pub const DCALL_FUNC: usize = 80;
|
||||
pub const VALUE_FUNC: usize = 90;
|
||||
pub const CREATE_FUNC: usize = 100;
|
||||
pub const SUICIDE_FUNC: usize = 110;
|
||||
pub const BLOCKHASH_FUNC: usize = 120;
|
||||
pub const BLOCKNUMBER_FUNC: usize = 130;
|
||||
pub const COINBASE_FUNC: usize = 140;
|
||||
pub const DIFFICULTY_FUNC: usize = 150;
|
||||
pub const GASLIMIT_FUNC: usize = 160;
|
||||
pub const TIMESTAMP_FUNC: usize = 170;
|
||||
pub const ADDRESS_FUNC: usize = 180;
|
||||
pub const SENDER_FUNC: usize = 190;
|
||||
pub const ORIGIN_FUNC: usize = 200;
|
||||
pub const ELOG_FUNC: usize = 210;
|
||||
|
||||
pub const PANIC_FUNC: usize = 1000;
|
||||
pub const DEBUG_FUNC: usize = 1010;
|
||||
}
|
||||
|
||||
/// Signatures of all functions runtime supports. The actual dispatch happens at
|
||||
/// impl runtime::Runtime methods.
|
||||
pub mod signatures {
|
||||
use wasmi::{self, ValueType};
|
||||
use wasmi::ValueType::*;
|
||||
|
||||
pub struct StaticSignature(pub &'static [ValueType], pub Option<ValueType>);
|
||||
|
||||
pub const STORAGE_READ: StaticSignature = StaticSignature(
|
||||
&[I32, I32],
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"_storage_write",
|
||||
&[I32; 2],
|
||||
);
|
||||
|
||||
pub const STORAGE_WRITE: StaticSignature = StaticSignature(
|
||||
&[I32, I32],
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"_balance",
|
||||
&[I32; 2],
|
||||
);
|
||||
|
||||
pub const RET: StaticSignature = StaticSignature(
|
||||
&[I32, I32],
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"_ext_malloc",
|
||||
);
|
||||
|
||||
pub const GAS: StaticSignature = StaticSignature(
|
||||
&[I32],
|
||||
None,
|
||||
);
|
||||
|
||||
pub const FETCH_INPUT: StaticSignature = StaticSignature(
|
||||
&[I32],
|
||||
None,
|
||||
);
|
||||
|
||||
pub const INPUT_LENGTH: StaticSignature = StaticSignature(
|
||||
&[],
|
||||
Some(I32),
|
||||
),
|
||||
Static(
|
||||
"_ext_free",
|
||||
&[I32],
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"gas",
|
||||
&[I32],
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"_debug",
|
||||
&[I32; 2],
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"_suicide",
|
||||
&[I32],
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"_create",
|
||||
&[I32; 4],
|
||||
Some(I32),
|
||||
),
|
||||
Static(
|
||||
"_ccall",
|
||||
);
|
||||
|
||||
pub const CCALL: StaticSignature = StaticSignature(
|
||||
&[I64, I32, I32, I32, I32, I32, I32],
|
||||
Some(I32),
|
||||
),
|
||||
Static(
|
||||
"_dcall",
|
||||
);
|
||||
|
||||
pub const DCALL: StaticSignature = StaticSignature(
|
||||
&[I64, I32, I32, I32, I32, I32],
|
||||
Some(I32),
|
||||
),
|
||||
Static(
|
||||
"_scall",
|
||||
);
|
||||
|
||||
pub const SCALL: StaticSignature = StaticSignature(
|
||||
&[I64, I32, I32, I32, I32, I32],
|
||||
Some(I32),
|
||||
),
|
||||
Static(
|
||||
"abort",
|
||||
);
|
||||
|
||||
pub const PANIC: StaticSignature = StaticSignature(
|
||||
&[I32, I32],
|
||||
None,
|
||||
);
|
||||
|
||||
pub const DEBUG: StaticSignature = StaticSignature(
|
||||
&[I32, I32],
|
||||
None,
|
||||
);
|
||||
|
||||
pub const VALUE: StaticSignature = StaticSignature(
|
||||
&[I32],
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"_emscripten_memcpy_big",
|
||||
&[I32; 3],
|
||||
);
|
||||
|
||||
pub const CREATE: StaticSignature = StaticSignature(
|
||||
&[I32, I32, I32, I32],
|
||||
Some(I32),
|
||||
),
|
||||
Static(
|
||||
"_ext_memcpy",
|
||||
&[I32; 3],
|
||||
Some(I32),
|
||||
),
|
||||
Static(
|
||||
"_ext_memset",
|
||||
&[I32; 3],
|
||||
Some(I32),
|
||||
),
|
||||
Static(
|
||||
"_ext_memmove",
|
||||
&[I32; 3],
|
||||
Some(I32),
|
||||
),
|
||||
Static(
|
||||
"_panic",
|
||||
&[I32; 2],
|
||||
);
|
||||
|
||||
pub const SUICIDE: StaticSignature = StaticSignature(
|
||||
&[I32],
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"_blockhash",
|
||||
);
|
||||
|
||||
pub const BLOCKHASH: StaticSignature = StaticSignature(
|
||||
&[I64, I32],
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"_coinbase",
|
||||
&[I32],
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"_sender",
|
||||
&[I32],
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"_origin",
|
||||
&[I32],
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"_address",
|
||||
&[I32],
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"_value",
|
||||
&[I32],
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"_timestamp",
|
||||
);
|
||||
|
||||
pub const BLOCKNUMBER: StaticSignature = StaticSignature(
|
||||
&[],
|
||||
Some(I64),
|
||||
),
|
||||
Static(
|
||||
"_blocknumber",
|
||||
);
|
||||
|
||||
pub const COINBASE: StaticSignature = StaticSignature(
|
||||
&[I32],
|
||||
None,
|
||||
);
|
||||
|
||||
pub const DIFFICULTY: StaticSignature = StaticSignature(
|
||||
&[I32],
|
||||
None,
|
||||
);
|
||||
|
||||
pub const GASLIMIT: StaticSignature = StaticSignature(
|
||||
&[I32],
|
||||
None,
|
||||
);
|
||||
|
||||
pub const TIMESTAMP: StaticSignature = StaticSignature(
|
||||
&[],
|
||||
Some(I64),
|
||||
),
|
||||
Static(
|
||||
"_difficulty",
|
||||
);
|
||||
|
||||
pub const ADDRESS: StaticSignature = StaticSignature(
|
||||
&[I32],
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"_gaslimit",
|
||||
);
|
||||
|
||||
pub const SENDER: StaticSignature = StaticSignature(
|
||||
&[I32],
|
||||
None,
|
||||
),
|
||||
Static(
|
||||
"_elog",
|
||||
&[I32; 4],
|
||||
);
|
||||
|
||||
pub const ORIGIN: StaticSignature = StaticSignature(
|
||||
&[I32],
|
||||
None,
|
||||
),
|
||||
);
|
||||
|
||||
// TODO: Get rid of it also somehow?
|
||||
Static(
|
||||
"_llvm_trap",
|
||||
&[I32; 0],
|
||||
None
|
||||
),
|
||||
pub const ELOG: StaticSignature = StaticSignature(
|
||||
&[I32, I32, I32, I32],
|
||||
None,
|
||||
);
|
||||
|
||||
Static(
|
||||
"_llvm_bswap_i64",
|
||||
&[I64],
|
||||
Some(I64)
|
||||
),
|
||||
];
|
||||
|
||||
pub fn native_bindings<'a>(runtime: &'a mut Runtime) -> interpreter::UserDefinedElements<'a, UserTrap> {
|
||||
interpreter::UserDefinedElements {
|
||||
executor: Some(runtime),
|
||||
globals: ::std::collections::HashMap::new(),
|
||||
functions: ::std::borrow::Cow::from(SIGNATURES),
|
||||
impl Into<wasmi::Signature> for StaticSignature {
|
||||
fn into(self) -> wasmi::Signature {
|
||||
wasmi::Signature::new(self.0, self.1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn host(signature: signatures::StaticSignature, idx: usize) -> FuncRef {
|
||||
FuncInstance::alloc_host(signature.into(), idx)
|
||||
}
|
||||
|
||||
/// Import resolver for wasmi
|
||||
/// Maps all functions that runtime support to the corresponding contract import
|
||||
/// entries.
|
||||
/// Also manages initial memory request from the runtime.
|
||||
#[derive(Default)]
|
||||
pub struct ImportResolver {
|
||||
max_memory: u32,
|
||||
memory: RefCell<Option<MemoryRef>>,
|
||||
}
|
||||
|
||||
impl ImportResolver {
|
||||
/// New import resolver with specifed maximum amount of inital memory (in wasm pages = 64kb)
|
||||
pub fn with_limit(max_memory: u32) -> ImportResolver {
|
||||
ImportResolver {
|
||||
max_memory: max_memory,
|
||||
memory: RefCell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns memory that was instantiated during the contract module
|
||||
/// start. If contract does not use memory at all, the dummy memory of length (0, 0)
|
||||
/// will be created instead. So this method always returns memory instance
|
||||
/// unless errored.
|
||||
pub fn memory_ref(&self) -> MemoryRef {
|
||||
{
|
||||
let mut mem_ref = self.memory.borrow_mut();
|
||||
if mem_ref.is_none() {
|
||||
*mem_ref = Some(
|
||||
MemoryInstance::alloc(0, Some(0)).expect("Memory allocation (0, 0) should not fail; qed")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
self.memory.borrow().clone().expect("it is either existed or was created as (0, 0) above; qed")
|
||||
}
|
||||
|
||||
/// Returns memory size module initially requested
|
||||
pub fn memory_size(&self) -> Result<u32, Error> {
|
||||
Ok(self.memory_ref().size())
|
||||
}
|
||||
}
|
||||
|
||||
impl wasmi::ModuleImportResolver for ImportResolver {
|
||||
fn resolve_func(&self, field_name: &str, _signature: &Signature) -> Result<FuncRef, Error> {
|
||||
let func_ref = match field_name {
|
||||
"storage_read" => host(signatures::STORAGE_READ, ids::STORAGE_READ_FUNC),
|
||||
"storage_write" => host(signatures::STORAGE_WRITE, ids::STORAGE_WRITE_FUNC),
|
||||
"ret" => host(signatures::RET, ids::RET_FUNC),
|
||||
"gas" => host(signatures::GAS, ids::GAS_FUNC),
|
||||
"input_length" => host(signatures::INPUT_LENGTH, ids::INPUT_LENGTH_FUNC),
|
||||
"fetch_input" => host(signatures::FETCH_INPUT, ids::FETCH_INPUT_FUNC),
|
||||
"panic" => host(signatures::PANIC, ids::PANIC_FUNC),
|
||||
"debug" => host(signatures::DEBUG, ids::DEBUG_FUNC),
|
||||
"ccall" => host(signatures::CCALL, ids::CCALL_FUNC),
|
||||
"dcall" => host(signatures::DCALL, ids::DCALL_FUNC),
|
||||
"scall" => host(signatures::SCALL, ids::SCALL_FUNC),
|
||||
"value" => host(signatures::VALUE, ids::VALUE_FUNC),
|
||||
"create" => host(signatures::CREATE, ids::CREATE_FUNC),
|
||||
"suicide" => host(signatures::SUICIDE, ids::SUICIDE_FUNC),
|
||||
"blockhash" => host(signatures::BLOCKHASH, ids::BLOCKHASH_FUNC),
|
||||
"blocknumber" => host(signatures::BLOCKNUMBER, ids::BLOCKNUMBER_FUNC),
|
||||
"coinbase" => host(signatures::COINBASE, ids::COINBASE_FUNC),
|
||||
"difficulty" => host(signatures::DIFFICULTY, ids::DIFFICULTY_FUNC),
|
||||
"gaslimit" => host(signatures::GASLIMIT, ids::GASLIMIT_FUNC),
|
||||
"timestamp" => host(signatures::TIMESTAMP, ids::TIMESTAMP_FUNC),
|
||||
"address" => host(signatures::ADDRESS, ids::ADDRESS_FUNC),
|
||||
"sender" => host(signatures::SENDER, ids::SENDER_FUNC),
|
||||
"origin" => host(signatures::ORIGIN, ids::ORIGIN_FUNC),
|
||||
"elog" => host(signatures::ELOG, ids::ELOG_FUNC),
|
||||
_ => {
|
||||
return Err(wasmi::Error::Instantiation(
|
||||
format!("Export {} not found", field_name),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
Ok(func_ref)
|
||||
}
|
||||
|
||||
fn resolve_memory(
|
||||
&self,
|
||||
field_name: &str,
|
||||
descriptor: &MemoryDescriptor,
|
||||
) -> Result<MemoryRef, Error> {
|
||||
if field_name == "memory" {
|
||||
let effective_max = descriptor.maximum().unwrap_or(self.max_memory + 1);
|
||||
if descriptor.initial() > self.max_memory || effective_max > self.max_memory
|
||||
{
|
||||
Err(Error::Instantiation("Module requested too much memory".to_owned()))
|
||||
} else {
|
||||
let mem = MemoryInstance::alloc(descriptor.initial(), descriptor.maximum())?;
|
||||
*self.memory.borrow_mut() = Some(mem.clone());
|
||||
Ok(mem)
|
||||
}
|
||||
} else {
|
||||
Err(Error::Instantiation("Memory imported under unknown name".to_owned()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,34 +16,30 @@
|
||||
|
||||
//! Wasm Interpreter
|
||||
|
||||
extern crate vm;
|
||||
extern crate byteorder;
|
||||
extern crate ethcore_logger;
|
||||
extern crate ethcore_util as util;
|
||||
extern crate ethcore_bigint as bigint;
|
||||
#[macro_use] extern crate log;
|
||||
extern crate ethcore_logger;
|
||||
extern crate byteorder;
|
||||
extern crate libc;
|
||||
extern crate parity_wasm;
|
||||
extern crate vm;
|
||||
extern crate wasm_utils;
|
||||
extern crate wasmi;
|
||||
|
||||
mod runtime;
|
||||
mod ptr;
|
||||
mod result;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod env;
|
||||
mod panic_payload;
|
||||
|
||||
const DEFAULT_STACK_SPACE: u32 = 5 * 1024 * 1024;
|
||||
|
||||
use parity_wasm::{interpreter, elements};
|
||||
use parity_wasm::interpreter::ModuleInstanceInterface;
|
||||
mod parser;
|
||||
|
||||
use vm::{GasLeft, ReturnData, ActionParams};
|
||||
use self::runtime::{Runtime, RuntimeContext, UserTrap};
|
||||
use wasmi::Error as InterpreterError;
|
||||
|
||||
pub use self::runtime::InterpreterError;
|
||||
use runtime::{Runtime, RuntimeContext};
|
||||
|
||||
const DEFAULT_RESULT_BUFFER: usize = 1024;
|
||||
use bigint::uint::U256;
|
||||
|
||||
/// Wrapped interpreter error
|
||||
#[derive(Debug)]
|
||||
@@ -61,139 +57,110 @@ impl From<Error> for vm::Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UserTrap> for vm::Error {
|
||||
fn from(e: UserTrap) -> Self { e.into() }
|
||||
}
|
||||
|
||||
/// Wasm interpreter instance
|
||||
pub struct WasmInterpreter {
|
||||
program: runtime::InterpreterProgramInstance,
|
||||
result: Vec<u8>,
|
||||
}
|
||||
pub struct WasmInterpreter;
|
||||
|
||||
impl WasmInterpreter {
|
||||
/// New wasm interpreter instance
|
||||
pub fn new() -> Result<WasmInterpreter, Error> {
|
||||
Ok(WasmInterpreter {
|
||||
program: interpreter::ProgramInstance::new()?,
|
||||
result: Vec::with_capacity(DEFAULT_RESULT_BUFFER),
|
||||
})
|
||||
impl From<runtime::Error> for vm::Error {
|
||||
fn from(e: runtime::Error) -> Self {
|
||||
vm::Error::Wasm(format!("Wasm runtime error: {:?}", e))
|
||||
}
|
||||
}
|
||||
|
||||
impl vm::Vm for WasmInterpreter {
|
||||
|
||||
fn exec(&mut self, params: ActionParams, ext: &mut vm::Ext) -> vm::Result<GasLeft> {
|
||||
use parity_wasm::elements::Deserialize;
|
||||
let (module, data) = parser::payload(¶ms, ext.schedule().wasm())?;
|
||||
|
||||
let code = params.code.expect("exec is only called on contract with code; qed");
|
||||
let loaded_module = wasmi::Module::from_parity_wasm_module(module).map_err(Error)?;
|
||||
|
||||
trace!(target: "wasm", "Started wasm interpreter with code.len={:?}", code.len());
|
||||
let instantiation_resolover = env::ImportResolver::with_limit(16);
|
||||
|
||||
let env_instance = self.program.module("env")
|
||||
// prefer explicit panic here
|
||||
.expect("Wasm program to contain env module");
|
||||
let module_instance = wasmi::ModuleInstance::new(
|
||||
&loaded_module,
|
||||
&wasmi::ImportsBuilder::new().with_resolver("env", &instantiation_resolover)
|
||||
).map_err(Error)?;
|
||||
|
||||
let env_memory = env_instance.memory(interpreter::ItemIndex::Internal(0))
|
||||
// prefer explicit panic here
|
||||
.expect("Linear memory to exist in wasm runtime");
|
||||
let adjusted_gas = params.gas * U256::from(ext.schedule().wasm().opcodes_div) /
|
||||
U256::from(ext.schedule().wasm().opcodes_mul);
|
||||
|
||||
if params.gas > ::std::u64::MAX.into() {
|
||||
return Err(vm::Error::Wasm("Wasm interpreter cannot run contracts with gas >= 2^64".to_owned()));
|
||||
if adjusted_gas > ::std::u64::MAX.into()
|
||||
{
|
||||
return Err(vm::Error::Wasm("Wasm interpreter cannot run contracts with gas (wasm adjusted) >= 2^64".to_owned()));
|
||||
}
|
||||
|
||||
let mut runtime = Runtime::with_params(
|
||||
ext,
|
||||
env_memory,
|
||||
DEFAULT_STACK_SPACE,
|
||||
params.gas.low_u64(),
|
||||
RuntimeContext {
|
||||
address: params.address,
|
||||
sender: params.sender,
|
||||
origin: params.origin,
|
||||
code_address: params.code_address,
|
||||
value: params.value.value(),
|
||||
},
|
||||
&self.program,
|
||||
);
|
||||
let initial_memory = instantiation_resolover.memory_size().map_err(Error)?;
|
||||
trace!(target: "wasm", "Contract requested {:?} pages of initial memory", initial_memory);
|
||||
|
||||
let (mut cursor, data_position) = match params.params_type {
|
||||
vm::ParamsType::Embedded => {
|
||||
let module_size = parity_wasm::peek_size(&*code);
|
||||
(
|
||||
::std::io::Cursor::new(&code[..module_size]),
|
||||
module_size
|
||||
)
|
||||
},
|
||||
vm::ParamsType::Separate => {
|
||||
(::std::io::Cursor::new(&code[..]), 0)
|
||||
},
|
||||
};
|
||||
|
||||
let contract_module = wasm_utils::inject_gas_counter(
|
||||
elements::Module::deserialize(
|
||||
&mut cursor
|
||||
).map_err(|err| {
|
||||
vm::Error::Wasm(format!("Error deserializing contract code ({:?})", err))
|
||||
})?,
|
||||
runtime.gas_rules(),
|
||||
);
|
||||
|
||||
let data_section_length = contract_module.data_section()
|
||||
.map(|section| section.entries().iter().fold(0, |sum, entry| sum + entry.value().len()))
|
||||
.unwrap_or(0)
|
||||
as u64;
|
||||
|
||||
let static_segment_cost = data_section_length * runtime.ext().schedule().wasm.static_region as u64;
|
||||
runtime.charge(|_| static_segment_cost).map_err(Error)?;
|
||||
|
||||
let d_ptr = {
|
||||
match params.params_type {
|
||||
vm::ParamsType::Embedded => {
|
||||
runtime.write_descriptor(
|
||||
if data_position < code.len() { &code[data_position..] } else { &[] }
|
||||
).map_err(Error)?
|
||||
let (gas_left, result) = {
|
||||
let mut runtime = Runtime::with_params(
|
||||
ext,
|
||||
instantiation_resolover.memory_ref(),
|
||||
// cannot overflow, checked above
|
||||
adjusted_gas.low_u64(),
|
||||
data.to_vec(),
|
||||
RuntimeContext {
|
||||
address: params.address,
|
||||
sender: params.sender,
|
||||
origin: params.origin,
|
||||
code_address: params.code_address,
|
||||
value: params.value.value(),
|
||||
},
|
||||
vm::ParamsType::Separate => {
|
||||
runtime.write_descriptor(¶ms.data.unwrap_or_default())
|
||||
.map_err(Error)?
|
||||
}
|
||||
}
|
||||
};
|
||||
);
|
||||
|
||||
{
|
||||
let execution_params = runtime.execution_params()
|
||||
.add_argument(interpreter::RuntimeValue::I32(d_ptr.as_raw() as i32));
|
||||
// cannot overflow if static_region < 2^16,
|
||||
// initial_memory ∈ [0..2^32)
|
||||
// total_charge <- static_region * 2^32 * 2^16
|
||||
// total_charge ∈ [0..2^64) if static_region ∈ [0..2^16)
|
||||
// qed
|
||||
assert!(runtime.schedule().wasm().initial_mem < 1 << 16);
|
||||
runtime.charge(|s| initial_memory as u64 * s.wasm().initial_mem as u64)?;
|
||||
|
||||
let module_instance = self.program.add_module("contract", contract_module, Some(&execution_params.externals))
|
||||
.map_err(|err| {
|
||||
trace!(target: "wasm", "Error adding contract module: {:?}", err);
|
||||
vm::Error::from(Error(err))
|
||||
})?;
|
||||
let module_instance = module_instance.run_start(&mut runtime).map_err(Error)?;
|
||||
|
||||
match module_instance.execute_export("_call", execution_params) {
|
||||
match module_instance.invoke_export("call", &[], &mut runtime) {
|
||||
Ok(_) => { },
|
||||
Err(interpreter::Error::User(UserTrap::Suicide)) => { },
|
||||
Err(InterpreterError::Host(boxed)) => {
|
||||
match boxed.downcast_ref::<runtime::Error>() {
|
||||
None => {
|
||||
return Err(vm::Error::Wasm("Invalid user error used in interpreter".to_owned()));
|
||||
}
|
||||
Some(runtime_err) => {
|
||||
match *runtime_err {
|
||||
runtime::Error::Suicide => {
|
||||
// Suicide uses trap to break execution
|
||||
}
|
||||
ref any_err => {
|
||||
trace!(target: "wasm", "Error executing contract: {:?}", boxed);
|
||||
return Err(vm::Error::from(Error::from(InterpreterError::Host(Box::new(any_err.clone())))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
trace!(target: "wasm", "Error executing contract: {:?}", err);
|
||||
return Err(vm::Error::from(Error(err)))
|
||||
return Err(vm::Error::from(Error::from(err)))
|
||||
}
|
||||
}
|
||||
}
|
||||
(
|
||||
runtime.gas_left().expect("Cannot fail since it was not updated since last charge"),
|
||||
runtime.into_result(),
|
||||
)
|
||||
};
|
||||
|
||||
let result = result::WasmResult::new(d_ptr);
|
||||
if result.peek_empty(&*runtime.memory()).map_err(|e| Error(e))? {
|
||||
let gas_left =
|
||||
U256::from(gas_left) * U256::from(ext.schedule().wasm().opcodes_mul)
|
||||
/ U256::from(ext.schedule().wasm().opcodes_div);
|
||||
|
||||
if result.is_empty() {
|
||||
trace!(target: "wasm", "Contract execution result is empty.");
|
||||
Ok(GasLeft::Known(runtime.gas_left()?.into()))
|
||||
Ok(GasLeft::Known(gas_left))
|
||||
} else {
|
||||
self.result.clear();
|
||||
// todo: use memory views to avoid copy
|
||||
self.result.extend(result.pop(&*runtime.memory()).map_err(|e| Error(e.into()))?);
|
||||
let len = self.result.len();
|
||||
let len = result.len();
|
||||
Ok(GasLeft::NeedsReturn {
|
||||
gas_left: runtime.gas_left().map_err(|e| Error(e.into()))?.into(),
|
||||
gas_left: gas_left,
|
||||
data: ReturnData::new(
|
||||
::std::mem::replace(&mut self.result, Vec::with_capacity(DEFAULT_RESULT_BUFFER)),
|
||||
result,
|
||||
0,
|
||||
len,
|
||||
),
|
||||
|
||||
89
ethcore/wasm/src/parser.rs
Normal file
@@ -0,0 +1,89 @@
|
||||
// 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/>.
|
||||
|
||||
//! ActionParams parser for wasm
|
||||
|
||||
use vm;
|
||||
use wasm_utils::{self, rules};
|
||||
use parity_wasm::elements::{self, Deserialize};
|
||||
use parity_wasm::peek_size;
|
||||
|
||||
fn gas_rules(wasm_costs: &vm::WasmCosts) -> rules::Set {
|
||||
rules::Set::new({
|
||||
let mut vals = ::std::collections::HashMap::with_capacity(4);
|
||||
vals.insert(rules::InstructionType::Load, wasm_costs.mem as u32);
|
||||
vals.insert(rules::InstructionType::Store, wasm_costs.mem as u32);
|
||||
vals.insert(rules::InstructionType::Div, wasm_costs.div as u32);
|
||||
vals.insert(rules::InstructionType::Mul, wasm_costs.mul as u32);
|
||||
vals
|
||||
}).with_grow_cost(wasm_costs.grow_mem)
|
||||
}
|
||||
|
||||
/// Splits payload to code and data according to params.params_type, also
|
||||
/// loads the module instance from payload and injects gas counter according
|
||||
/// to schedule.
|
||||
pub fn payload<'a>(params: &'a vm::ActionParams, wasm_costs: &vm::WasmCosts)
|
||||
-> Result<(elements::Module, &'a [u8]), vm::Error>
|
||||
{
|
||||
let code = match params.code {
|
||||
Some(ref code) => &code[..],
|
||||
None => { return Err(vm::Error::Wasm("Invalid wasm call".to_owned())); }
|
||||
};
|
||||
|
||||
let (mut cursor, data_position) = match params.params_type {
|
||||
vm::ParamsType::Embedded => {
|
||||
let module_size = peek_size(&*code);
|
||||
(
|
||||
::std::io::Cursor::new(&code[..module_size]),
|
||||
module_size
|
||||
)
|
||||
},
|
||||
vm::ParamsType::Separate => {
|
||||
(::std::io::Cursor::new(&code[..]), 0)
|
||||
},
|
||||
};
|
||||
|
||||
let deserialized_module = elements::Module::deserialize(
|
||||
&mut cursor
|
||||
).map_err(|err| {
|
||||
vm::Error::Wasm(format!("Error deserializing contract code ({:?})", err))
|
||||
})?;
|
||||
|
||||
if deserialized_module.memory_section().map_or(false, |ms| ms.entries().len() > 0) {
|
||||
// According to WebAssembly spec, internal memory is hidden from embedder and should not
|
||||
// be interacted with. So we disable this kind of modules at decoding level.
|
||||
return Err(vm::Error::Wasm(format!("Malformed wasm module: internal memory")));
|
||||
}
|
||||
|
||||
let contract_module = wasm_utils::inject_gas_counter(
|
||||
deserialized_module,
|
||||
&gas_rules(wasm_costs),
|
||||
);
|
||||
|
||||
let data = match params.params_type {
|
||||
vm::ParamsType::Embedded => {
|
||||
if data_position < code.len() { &code[data_position..] } else { &[] }
|
||||
},
|
||||
vm::ParamsType::Separate => {
|
||||
match params.data {
|
||||
Some(ref s) => &s[..],
|
||||
None => &[]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok((contract_module, data))
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Wasm bound-checked ptr
|
||||
|
||||
use super::runtime::{InterpreterMemoryInstance, InterpreterError, UserTrap};
|
||||
|
||||
/// Bound-checked wrapper for webassembly memory
|
||||
pub struct WasmPtr(u32);
|
||||
|
||||
/// Error in bound check
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
AccessViolation,
|
||||
}
|
||||
|
||||
impl From<u32> for WasmPtr {
|
||||
fn from(raw: u32) -> Self {
|
||||
WasmPtr(raw)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for InterpreterError {
|
||||
fn from(_e: Error) -> Self {
|
||||
UserTrap::MemoryAccessViolation.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl WasmPtr {
|
||||
// todo: use memory view when they are on
|
||||
/// Check memory range and return data with given length starting from the current pointer value
|
||||
pub fn slice(&self, len: u32, mem: &InterpreterMemoryInstance) -> Result<Vec<u8>, Error> {
|
||||
mem.get(self.0, len as usize).map_err(|_| Error::AccessViolation)
|
||||
}
|
||||
|
||||
// todo: maybe 2gb limit can be enhanced
|
||||
/// Convert i32 from wasm stack to the wrapped pointer
|
||||
pub fn from_i32(raw_ptr: i32) -> Result<Self, Error> {
|
||||
if raw_ptr < 0 { return Err(Error::AccessViolation); }
|
||||
Ok(WasmPtr(raw_ptr as u32))
|
||||
}
|
||||
|
||||
/// Return pointer raw value
|
||||
pub fn as_raw(&self) -> u32 { self.0 }
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Wasm evm results helper
|
||||
|
||||
use byteorder::{LittleEndian, ByteOrder};
|
||||
|
||||
use super::ptr::WasmPtr;
|
||||
use super::runtime::{InterpreterError, InterpreterMemoryInstance};
|
||||
|
||||
/// Wrapper for wasm contract call result
|
||||
pub struct WasmResult {
|
||||
ptr: WasmPtr,
|
||||
}
|
||||
|
||||
impl WasmResult {
|
||||
/// New call result from given ptr
|
||||
pub fn new(descriptor_ptr: WasmPtr) -> WasmResult {
|
||||
WasmResult { ptr: descriptor_ptr }
|
||||
}
|
||||
|
||||
/// Check if the result contains any data
|
||||
pub fn peek_empty(&self, mem: &InterpreterMemoryInstance) -> Result<bool, InterpreterError> {
|
||||
let result_len = LittleEndian::read_u32(&self.ptr.slice(16, mem)?[12..16]);
|
||||
Ok(result_len == 0)
|
||||
}
|
||||
|
||||
/// Consume the result ptr and return the actual data from wasm linear memory
|
||||
pub fn pop(self, mem: &InterpreterMemoryInstance) -> Result<Vec<u8>, InterpreterError> {
|
||||
let result_ptr = LittleEndian::read_u32(&self.ptr.slice(16, mem)?[8..12]);
|
||||
let result_len = LittleEndian::read_u32(&self.ptr.slice(16, mem)?[12..16]);
|
||||
trace!(target: "wasm", "contract result: {} bytes at @{}", result_len, result_ptr);
|
||||
|
||||
Ok(mem.get(result_ptr, result_len as usize)?)
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,34 @@ macro_rules! load_sample {
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! reqrep_test {
|
||||
($name: expr, $input: expr) => {
|
||||
reqrep_test!($name, $input, vm::EnvInfo::default(), HashMap::new())
|
||||
};
|
||||
($name: expr, $input: expr, $info: expr, $block_hashes: expr) => {
|
||||
{
|
||||
::ethcore_logger::init_log();
|
||||
let code = load_sample!($name);
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.data = Some($input);
|
||||
|
||||
let mut fake_ext = FakeExt::new().with_wasm();
|
||||
fake_ext.info = $info;
|
||||
fake_ext.blockhashes = $block_hashes;
|
||||
|
||||
let mut interpreter = wasm_interpreter();
|
||||
interpreter.exec(params, &mut fake_ext)
|
||||
.map(|result| match result {
|
||||
GasLeft::Known(_) => { panic!("Test is expected to return payload to check"); },
|
||||
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn test_finalize(res: Result<GasLeft, vm::Error>) -> Result<U256, vm::Error> {
|
||||
match res {
|
||||
Ok(GasLeft::Known(gas)) => Ok(gas),
|
||||
@@ -40,7 +68,7 @@ fn test_finalize(res: Result<GasLeft, vm::Error>) -> Result<U256, vm::Error> {
|
||||
}
|
||||
|
||||
fn wasm_interpreter() -> WasmInterpreter {
|
||||
WasmInterpreter::new().expect("wasm interpreter to create without errors")
|
||||
WasmInterpreter
|
||||
}
|
||||
|
||||
/// Empty contract does almost nothing except producing 1 (one) local node debug log message
|
||||
@@ -53,14 +81,14 @@ fn empty() {
|
||||
params.address = address.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
let mut ext = FakeExt::new().with_wasm();
|
||||
|
||||
let gas_left = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
test_finalize(interpreter.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
assert_eq!(gas_left, U256::from(96_678));
|
||||
assert_eq!(gas_left, U256::from(98462));
|
||||
}
|
||||
|
||||
// This test checks if the contract deserializes payload header properly.
|
||||
@@ -82,7 +110,7 @@ fn logger() {
|
||||
params.gas = U256::from(100_000);
|
||||
params.value = ActionValue::transfer(1_000_000_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
let mut ext = FakeExt::new().with_wasm();
|
||||
|
||||
let gas_left = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
@@ -112,7 +140,7 @@ fn logger() {
|
||||
U256::from(1_000_000_000),
|
||||
"Logger sets 0x04 key to the trasferred value"
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(15_860));
|
||||
assert_eq!(gas_left, U256::from(17_578));
|
||||
}
|
||||
|
||||
// This test checks if the contract can allocate memory and pass pointer to the result stream properly.
|
||||
@@ -131,7 +159,7 @@ fn identity() {
|
||||
params.sender = sender.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
let mut ext = FakeExt::new().with_wasm();
|
||||
|
||||
let (gas_left, result) = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
@@ -147,7 +175,7 @@ fn identity() {
|
||||
sender,
|
||||
"Idenity test contract does not return the sender passed"
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(96_540));
|
||||
assert_eq!(gas_left, U256::from(98_408));
|
||||
}
|
||||
|
||||
// Dispersion test sends byte array and expect the contract to 'disperse' the original elements with
|
||||
@@ -156,6 +184,8 @@ fn identity() {
|
||||
// This also tests byte-perfect memory allocation and in/out ptr lifecycle.
|
||||
#[test]
|
||||
fn dispersion() {
|
||||
::ethcore_logger::init_log();
|
||||
|
||||
let code = load_sample!("dispersion.wasm");
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
@@ -164,7 +194,7 @@ fn dispersion() {
|
||||
params.data = Some(vec![
|
||||
0u8, 125, 197, 255, 19
|
||||
]);
|
||||
let mut ext = FakeExt::new();
|
||||
let mut ext = FakeExt::new().with_wasm();
|
||||
|
||||
let (gas_left, result) = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
@@ -175,12 +205,11 @@ fn dispersion() {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
vec![0u8, 0, 125, 11, 197, 7, 255, 8, 19, 0]
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(96_116));
|
||||
assert_eq!(gas_left, U256::from(93_972));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -193,7 +222,7 @@ fn suicide_not() {
|
||||
params.data = Some(vec![
|
||||
0u8
|
||||
]);
|
||||
let mut ext = FakeExt::new();
|
||||
let mut ext = FakeExt::new().with_wasm();
|
||||
|
||||
let (gas_left, result) = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
@@ -208,7 +237,7 @@ fn suicide_not() {
|
||||
result,
|
||||
vec![0u8]
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(96_461));
|
||||
assert_eq!(gas_left, U256::from(94_970));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -226,7 +255,7 @@ fn suicide() {
|
||||
args.extend(refund.to_vec());
|
||||
params.data = Some(args);
|
||||
|
||||
let mut ext = FakeExt::new();
|
||||
let mut ext = FakeExt::new().with_wasm();
|
||||
|
||||
let gas_left = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
@@ -240,7 +269,7 @@ fn suicide() {
|
||||
};
|
||||
|
||||
assert!(ext.suicides.contains(&refund));
|
||||
assert_eq!(gas_left, U256::from(96_429));
|
||||
assert_eq!(gas_left, U256::from(94_933));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -253,7 +282,7 @@ fn create() {
|
||||
params.data = Some(vec![0u8, 2, 4, 8, 16, 32, 64, 128]);
|
||||
params.value = ActionValue::transfer(1_000_000_000);
|
||||
|
||||
let mut ext = FakeExt::new();
|
||||
let mut ext = FakeExt::new().with_wasm();
|
||||
|
||||
let gas_left = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
@@ -270,7 +299,7 @@ fn create() {
|
||||
assert!(ext.calls.contains(
|
||||
&FakeCall {
|
||||
call_type: FakeCallType::Create,
|
||||
gas: U256::from(62_545),
|
||||
gas: U256::from(60_917),
|
||||
sender_address: None,
|
||||
receive_address: None,
|
||||
value: Some(1_000_000_000.into()),
|
||||
@@ -278,7 +307,7 @@ fn create() {
|
||||
code_address: None,
|
||||
}
|
||||
));
|
||||
assert_eq!(gas_left, U256::from(62_538));
|
||||
assert_eq!(gas_left, U256::from(60_903));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -297,7 +326,7 @@ fn call_msg() {
|
||||
params.code = Some(Arc::new(load_sample!("call.wasm")));
|
||||
params.data = Some(Vec::new());
|
||||
|
||||
let mut ext = FakeExt::new();
|
||||
let mut ext = FakeExt::new().with_wasm();
|
||||
ext.balances.insert(receiver.clone(), U256::from(10000000000u64));
|
||||
|
||||
let gas_left = {
|
||||
@@ -322,7 +351,7 @@ fn call_msg() {
|
||||
}
|
||||
));
|
||||
|
||||
assert_eq!(gas_left, U256::from(95_699));
|
||||
assert_eq!(gas_left, U256::from(93_511));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -340,7 +369,7 @@ fn call_code() {
|
||||
params.data = Some(Vec::new());
|
||||
params.value = ActionValue::transfer(1_000_000_000);
|
||||
|
||||
let mut ext = FakeExt::new();
|
||||
let mut ext = FakeExt::new().with_wasm();
|
||||
|
||||
let (gas_left, result) = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
@@ -367,7 +396,7 @@ fn call_code() {
|
||||
// siphash result
|
||||
let res = LittleEndian::read_u32(&result[..]);
|
||||
assert_eq!(res, 4198595614);
|
||||
assert_eq!(gas_left, U256::from(90_550));
|
||||
assert_eq!(gas_left, U256::from(92_381));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -387,7 +416,7 @@ fn call_static() {
|
||||
params.value = ActionValue::transfer(1_000_000_000);
|
||||
params.code_address = contract_address.clone();
|
||||
|
||||
let mut ext = FakeExt::new();
|
||||
let mut ext = FakeExt::new().with_wasm();
|
||||
|
||||
let (gas_left, result) = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
@@ -415,7 +444,7 @@ fn call_static() {
|
||||
let res = LittleEndian::read_u32(&result[..]);
|
||||
assert_eq!(res, 317632590);
|
||||
|
||||
assert_eq!(gas_left, U256::from(90_550));
|
||||
assert_eq!(gas_left, U256::from(92_381));
|
||||
}
|
||||
|
||||
// Realloc test
|
||||
@@ -427,7 +456,7 @@ fn realloc() {
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.data = Some(vec![0u8]);
|
||||
let mut ext = FakeExt::new();
|
||||
let mut ext = FakeExt::new().with_wasm();
|
||||
|
||||
let (gas_left, result) = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
@@ -438,20 +467,44 @@ fn realloc() {
|
||||
}
|
||||
};
|
||||
assert_eq!(result, vec![0u8; 2]);
|
||||
assert_eq!(gas_left, U256::from(96_445));
|
||||
assert_eq!(gas_left, U256::from(94_352));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alloc() {
|
||||
let code = load_sample!("alloc.wasm");
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(10_000_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.data = Some(vec![0u8]);
|
||||
let mut ext = FakeExt::new().with_wasm();
|
||||
|
||||
let (gas_left, result) = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
||||
match result {
|
||||
GasLeft::Known(_) => { panic!("alloc test should return payload"); },
|
||||
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||
}
|
||||
};
|
||||
assert_eq!(result, vec![5u8; 1024*450]);
|
||||
assert_eq!(gas_left, U256::from(6_506_844));
|
||||
}
|
||||
|
||||
// Tests that contract's ability to read from a storage
|
||||
// Test prepopulates address into storage, than executes a contract which read that address from storage and write this address into result
|
||||
#[test]
|
||||
fn storage_read() {
|
||||
::ethcore_logger::init_log();
|
||||
|
||||
let code = load_sample!("storage_read.wasm");
|
||||
let address: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
let mut ext = FakeExt::new();
|
||||
let mut ext = FakeExt::new().with_wasm();
|
||||
ext.store.insert("0100000000000000000000000000000000000000000000000000000000000000".into(), address.into());
|
||||
|
||||
let (gas_left, result) = {
|
||||
@@ -464,7 +517,7 @@ fn storage_read() {
|
||||
};
|
||||
|
||||
assert_eq!(Address::from(&result[12..32]), address);
|
||||
assert_eq!(gas_left, U256::from(96_463));
|
||||
assert_eq!(gas_left, U256::from(98_298));
|
||||
}
|
||||
|
||||
// Tests keccak calculation
|
||||
@@ -478,7 +531,7 @@ fn keccak() {
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.data = Some(b"something".to_vec());
|
||||
let mut ext = FakeExt::new();
|
||||
let mut ext = FakeExt::new().with_wasm();
|
||||
|
||||
let (gas_left, result) = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
@@ -490,124 +543,7 @@ fn keccak() {
|
||||
};
|
||||
|
||||
assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
|
||||
assert_eq!(gas_left, U256::from(81_067));
|
||||
}
|
||||
|
||||
// memcpy test.
|
||||
#[test]
|
||||
fn memcpy() {
|
||||
::ethcore_logger::init_log();
|
||||
let code = load_sample!("mem.wasm");
|
||||
|
||||
let mut test_payload = Vec::with_capacity(8192);
|
||||
for i in 0..8192 {
|
||||
test_payload.push((i % 255) as u8);
|
||||
}
|
||||
let mut data = vec![0u8];
|
||||
data.extend(&test_payload);
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.data = Some(data);
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let (gas_left, result) = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
||||
match result {
|
||||
GasLeft::Known(_) => { panic!("mem should return payload"); },
|
||||
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||
}
|
||||
};
|
||||
|
||||
assert_eq!(result, test_payload);
|
||||
assert_eq!(gas_left, U256::from(71_940));
|
||||
}
|
||||
|
||||
// memmove test.
|
||||
#[test]
|
||||
fn memmove() {
|
||||
::ethcore_logger::init_log();
|
||||
let code = load_sample!("mem.wasm");
|
||||
|
||||
let mut test_payload = Vec::with_capacity(8192);
|
||||
for i in 0..8192 {
|
||||
test_payload.push((i % 255) as u8);
|
||||
}
|
||||
let mut data = vec![1u8];
|
||||
data.extend(&test_payload);
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.data = Some(data);
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let (gas_left, result) = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
||||
match result {
|
||||
GasLeft::Known(_) => { panic!("mem should return payload"); },
|
||||
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||
}
|
||||
};
|
||||
|
||||
assert_eq!(result, test_payload);
|
||||
assert_eq!(gas_left, U256::from(71_940));
|
||||
}
|
||||
|
||||
// memset test
|
||||
#[test]
|
||||
fn memset() {
|
||||
::ethcore_logger::init_log();
|
||||
let code = load_sample!("mem.wasm");
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.data = Some(vec![2u8, 228u8]);
|
||||
let mut ext = FakeExt::new();
|
||||
|
||||
let (gas_left, result) = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
||||
match result {
|
||||
GasLeft::Known(_) => { panic!("mem should return payload"); },
|
||||
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||
}
|
||||
};
|
||||
|
||||
assert_eq!(result, vec![228u8; 8192]);
|
||||
assert_eq!(gas_left, U256::from(71_921));
|
||||
}
|
||||
|
||||
macro_rules! reqrep_test {
|
||||
($name: expr, $input: expr) => {
|
||||
reqrep_test!($name, $input, vm::EnvInfo::default(), HashMap::new())
|
||||
};
|
||||
($name: expr, $input: expr, $info: expr, $block_hashes: expr) => {
|
||||
{
|
||||
::ethcore_logger::init_log();
|
||||
let code = load_sample!($name);
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.data = Some($input);
|
||||
|
||||
let mut fake_ext = FakeExt::new();
|
||||
fake_ext.info = $info;
|
||||
fake_ext.blockhashes = $block_hashes;
|
||||
|
||||
let mut interpreter = wasm_interpreter();
|
||||
interpreter.exec(params, &mut fake_ext)
|
||||
.map(|result| match result {
|
||||
GasLeft::Known(_) => { panic!("Test is expected to return payload to check"); },
|
||||
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||
})
|
||||
}
|
||||
};
|
||||
assert_eq!(gas_left, U256::from(84_223));
|
||||
}
|
||||
|
||||
// math_* tests check the ability of wasm contract to perform big integer operations
|
||||
@@ -636,7 +572,7 @@ fn math_add() {
|
||||
U256::from_dec_str("1888888888888888888888888888887").unwrap(),
|
||||
(&result[..]).into()
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(95_384));
|
||||
assert_eq!(gas_left, U256::from(93_818));
|
||||
}
|
||||
|
||||
// multiplication
|
||||
@@ -658,7 +594,7 @@ fn math_mul() {
|
||||
U256::from_dec_str("888888888888888888888888888887111111111111111111111111111112").unwrap(),
|
||||
(&result[..]).into()
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(94_374));
|
||||
assert_eq!(gas_left, U256::from(93_304));
|
||||
}
|
||||
|
||||
// subtraction
|
||||
@@ -680,7 +616,7 @@ fn math_sub() {
|
||||
U256::from_dec_str("111111111111111111111111111111").unwrap(),
|
||||
(&result[..]).into()
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(95_372));
|
||||
assert_eq!(gas_left, U256::from(93_831));
|
||||
}
|
||||
|
||||
// subtraction with overflow
|
||||
@@ -722,7 +658,54 @@ fn math_div() {
|
||||
U256::from_dec_str("1125000").unwrap(),
|
||||
(&result[..]).into()
|
||||
);
|
||||
assert_eq!(gas_left, U256::from(88_356));
|
||||
assert_eq!(gas_left, U256::from(90_607));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn storage_metering() {
|
||||
::ethcore_logger::init_log();
|
||||
|
||||
// #1
|
||||
let mut ext = FakeExt::new().with_wasm();
|
||||
|
||||
let code = Arc::new(load_sample!("setter.wasm"));
|
||||
let address: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.address = address.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code.clone());
|
||||
params.data = Some(vec![
|
||||
0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
|
||||
0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b,
|
||||
]);
|
||||
|
||||
let gas_left = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
test_finalize(interpreter.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
// 0 -> not 0
|
||||
assert_eq!(gas_left, U256::from(74_410));
|
||||
|
||||
// #2
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.address = address.clone();
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code.clone());
|
||||
params.data = Some(vec![
|
||||
0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
|
||||
0x6b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b,
|
||||
]);
|
||||
|
||||
let gas_left = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
test_finalize(interpreter.exec(params, &mut ext)).unwrap()
|
||||
};
|
||||
|
||||
// not 0 -> not 0
|
||||
assert_eq!(gas_left, U256::from(89_410));
|
||||
}
|
||||
|
||||
// This test checks the ability of wasm contract to invoke
|
||||
@@ -810,7 +793,7 @@ fn externs() {
|
||||
"Gas limit requested and returned does not match"
|
||||
);
|
||||
|
||||
assert_eq!(gas_left, U256::from(95_321));
|
||||
assert_eq!(gas_left, U256::from(92_089));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -824,7 +807,7 @@ fn embedded_keccak() {
|
||||
params.code = Some(Arc::new(code));
|
||||
params.params_type = vm::ParamsType::Embedded;
|
||||
|
||||
let mut ext = FakeExt::new();
|
||||
let mut ext = FakeExt::new().with_wasm();
|
||||
|
||||
let (gas_left, result) = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
@@ -836,7 +819,7 @@ fn embedded_keccak() {
|
||||
};
|
||||
|
||||
assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
|
||||
assert_eq!(gas_left, U256::from(81_067));
|
||||
assert_eq!(gas_left, U256::from(84_223));
|
||||
}
|
||||
|
||||
/// This test checks the correctness of log extern
|
||||
@@ -852,7 +835,7 @@ fn events() {
|
||||
params.code = Some(Arc::new(code));
|
||||
params.data = Some(b"something".to_vec());
|
||||
|
||||
let mut ext = FakeExt::new();
|
||||
let mut ext = FakeExt::new().with_wasm();
|
||||
|
||||
let (gas_left, result) = {
|
||||
let mut interpreter = wasm_interpreter();
|
||||
@@ -871,5 +854,5 @@ fn events() {
|
||||
assert_eq!(&log_entry.data, b"gnihtemos");
|
||||
|
||||
assert_eq!(&result, b"gnihtemos");
|
||||
assert_eq!(gas_left, U256::from(79_206));
|
||||
assert_eq!(gas_left, U256::from(81_235));
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::{fs, io};
|
||||
use std::io::Write;
|
||||
use std::path::{PathBuf, Path};
|
||||
use std::collections::HashMap;
|
||||
use time;
|
||||
@@ -152,31 +153,39 @@ impl<T> DiskDirectory<T> where T: KeyFileManager {
|
||||
)
|
||||
}
|
||||
|
||||
/// insert account with given file name
|
||||
pub fn insert_with_filename(&self, account: SafeAccount, filename: String) -> Result<SafeAccount, Error> {
|
||||
|
||||
/// insert account with given filename. if the filename is a duplicate of any stored account and dedup is set to
|
||||
/// true, a random suffix is appended to the filename.
|
||||
pub fn insert_with_filename(&self, account: SafeAccount, mut filename: String, dedup: bool) -> Result<SafeAccount, Error> {
|
||||
// path to keyfile
|
||||
let mut keyfile_path = self.path.join(filename.as_str());
|
||||
|
||||
// check for duplicate filename and append random suffix
|
||||
if dedup && keyfile_path.exists() {
|
||||
let suffix = ::random::random_string(4);
|
||||
filename.push_str(&format!("-{}", suffix));
|
||||
keyfile_path.set_file_name(&filename);
|
||||
}
|
||||
|
||||
// update account filename
|
||||
let original_account = account.clone();
|
||||
let mut account = account;
|
||||
account.filename = Some(filename.clone());
|
||||
account.filename = Some(filename);
|
||||
|
||||
{
|
||||
// Path to keyfile
|
||||
let mut keyfile_path = self.path.clone();
|
||||
keyfile_path.push(filename.as_str());
|
||||
|
||||
// save the file
|
||||
let mut file = fs::File::create(&keyfile_path)?;
|
||||
if let Err(err) = self.key_manager.write(original_account, &mut file).map_err(|e| Error::Custom(format!("{:?}", e))) {
|
||||
drop(file);
|
||||
fs::remove_file(keyfile_path).expect("Expected to remove recently created file");
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
// write key content
|
||||
self.key_manager.write(original_account, &mut file).map_err(|e| Error::Custom(format!("{:?}", e)))?;
|
||||
|
||||
file.flush()?;
|
||||
|
||||
if let Err(_) = restrict_permissions_to_owner(keyfile_path.as_path()) {
|
||||
drop(file);
|
||||
fs::remove_file(keyfile_path).expect("Expected to remove recently created file");
|
||||
return Err(Error::Io(io::Error::last_os_error()));
|
||||
}
|
||||
|
||||
file.sync_all()?;
|
||||
}
|
||||
|
||||
Ok(account)
|
||||
@@ -199,17 +208,13 @@ impl<T> KeyDirectory for DiskDirectory<T> where T: KeyFileManager {
|
||||
|
||||
fn update(&self, account: SafeAccount) -> Result<SafeAccount, Error> {
|
||||
// Disk store handles updates correctly iff filename is the same
|
||||
self.insert(account)
|
||||
let filename = account_filename(&account);
|
||||
self.insert_with_filename(account, filename, false)
|
||||
}
|
||||
|
||||
fn insert(&self, account: SafeAccount) -> Result<SafeAccount, Error> {
|
||||
// build file path
|
||||
let filename = account.filename.as_ref().cloned().unwrap_or_else(|| {
|
||||
let timestamp = time::strftime("%Y-%m-%dT%H-%M-%S", &time::now_utc()).expect("Time-format string is valid.");
|
||||
format!("UTC--{}Z--{}", timestamp, Uuid::from(account.id))
|
||||
});
|
||||
|
||||
self.insert_with_filename(account, filename)
|
||||
let filename = account_filename(&account);
|
||||
self.insert_with_filename(account, filename, true)
|
||||
}
|
||||
|
||||
fn remove(&self, account: &SafeAccount) -> Result<(), Error> {
|
||||
@@ -285,6 +290,14 @@ impl KeyFileManager for DiskKeyFileManager {
|
||||
}
|
||||
}
|
||||
|
||||
fn account_filename(account: &SafeAccount) -> String {
|
||||
// build file path
|
||||
account.filename.clone().unwrap_or_else(|| {
|
||||
let timestamp = time::strftime("%Y-%m-%dT%H-%M-%S", &time::now_utc()).expect("Time-format string is valid.");
|
||||
format!("UTC--{}Z--{}", timestamp, Uuid::from(account.id))
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
extern crate tempdir;
|
||||
@@ -316,6 +329,38 @@ mod test {
|
||||
let _ = fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_handle_duplicate_filenames() {
|
||||
// given
|
||||
let mut dir = env::temp_dir();
|
||||
dir.push("ethstore_should_handle_duplicate_filenames");
|
||||
let keypair = Random.generate().unwrap();
|
||||
let password = "hello world";
|
||||
let directory = RootDiskDirectory::create(dir.clone()).unwrap();
|
||||
|
||||
// when
|
||||
let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned());
|
||||
let filename = "test".to_string();
|
||||
let dedup = true;
|
||||
|
||||
directory.insert_with_filename(account.clone(), "foo".to_string(), dedup).unwrap();
|
||||
let file1 = directory.insert_with_filename(account.clone(), filename.clone(), dedup).unwrap().filename.unwrap();
|
||||
let file2 = directory.insert_with_filename(account.clone(), filename.clone(), dedup).unwrap().filename.unwrap();
|
||||
let file3 = directory.insert_with_filename(account.clone(), filename.clone(), dedup).unwrap().filename.unwrap();
|
||||
|
||||
// then
|
||||
// the first file should have the original names
|
||||
assert_eq!(file1, filename);
|
||||
|
||||
// the following duplicate files should have a suffix appended
|
||||
assert!(file2 != file3);
|
||||
assert_eq!(file2.len(), filename.len() + 5);
|
||||
assert_eq!(file3.len(), filename.len() + 5);
|
||||
|
||||
// cleanup
|
||||
let _ = fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_manage_vaults() {
|
||||
// given
|
||||
|
||||
@@ -106,7 +106,7 @@ impl VaultDiskDirectory {
|
||||
fn copy_to_vault(&self, vault: &VaultDiskDirectory) -> Result<(), Error> {
|
||||
for account in self.load()? {
|
||||
let filename = account.filename.clone().expect("self is instance of DiskDirectory; DiskDirectory fills filename in load; qed");
|
||||
vault.insert_with_filename(account, filename)?;
|
||||
vault.insert_with_filename(account, filename, true)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -166,9 +166,14 @@ impl SecretStore for EthStore {
|
||||
self.insert_account(vault, keypair.secret().clone(), password)
|
||||
}
|
||||
|
||||
fn import_wallet(&self, vault: SecretVaultRef, json: &[u8], password: &str) -> Result<StoreAccountRef, Error> {
|
||||
fn import_wallet(&self, vault: SecretVaultRef, json: &[u8], password: &str, gen_id: bool) -> Result<StoreAccountRef, Error> {
|
||||
let json_keyfile = json::KeyFile::load(json).map_err(|_| Error::InvalidKeyFile("Invalid JSON format".to_owned()))?;
|
||||
let mut safe_account = SafeAccount::from_file(json_keyfile, None);
|
||||
|
||||
if gen_id {
|
||||
safe_account.id = Random::random();
|
||||
}
|
||||
|
||||
let secret = safe_account.crypto.secret(password).map_err(|_| Error::InvalidPassword)?;
|
||||
safe_account.address = KeyPair::from_secret(secret)?.address();
|
||||
self.store.import(vault, safe_account)
|
||||
|
||||
@@ -116,7 +116,7 @@ pub trait SecretStore: SimpleSecretStore {
|
||||
/// Imports presale wallet
|
||||
fn import_presale(&self, vault: SecretVaultRef, json: &[u8], password: &str) -> Result<StoreAccountRef, Error>;
|
||||
/// Imports existing JSON wallet
|
||||
fn import_wallet(&self, vault: SecretVaultRef, json: &[u8], password: &str) -> Result<StoreAccountRef, Error>;
|
||||
fn import_wallet(&self, vault: SecretVaultRef, json: &[u8], password: &str, gen_id: bool) -> Result<StoreAccountRef, Error>;
|
||||
/// Copies account between stores and vaults.
|
||||
fn copy_account(&self, new_store: &SimpleSecretStore, new_vault: SecretVaultRef, account: &StoreAccountRef, password: &str, new_password: &str) -> Result<(), Error>;
|
||||
/// Checks if password matches given account.
|
||||
|
||||
58
js-old/package-lock.json
generated
@@ -7522,7 +7522,7 @@
|
||||
}
|
||||
},
|
||||
"jsqr": {
|
||||
"version": "git+https://github.com/JodusNodus/jsQR.git#5ba1acefa1cbb9b2bc92b49f503f2674e2ec212b"
|
||||
"version": "git+https://github.com/cozmo/jsQR.git#1fb946a235abdc7709f04cd0e4aa316a3b6eae70"
|
||||
},
|
||||
"jsx-ast-utils": {
|
||||
"version": "1.4.1",
|
||||
@@ -10576,13 +10576,29 @@
|
||||
}
|
||||
},
|
||||
"react-qr-reader": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/react-qr-reader/-/react-qr-reader-1.1.3.tgz",
|
||||
"integrity": "sha512-ruBF8KaSwUW9nbzjO4rA7/HOCGYZuNUz9od7uBRy8SRBi24nwxWWmwa2z8R6vPGDRglA0y2Qk1aVBuC1olTnHw==",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-qr-reader/-/react-qr-reader-2.0.1.tgz",
|
||||
"integrity": "sha512-J/VuCq/udEqry7Z4nXGTbguetfSdRJr1Cv0lYKbVKIW1blfhB0Xe6OjO+5Th5B8884+s40BDFwtqP67h7YTtYA==",
|
||||
"requires": {
|
||||
"jsqr": "git+https://github.com/JodusNodus/jsQR.git#5ba1acefa1cbb9b2bc92b49f503f2674e2ec212b",
|
||||
"jsqr": "git+https://github.com/cozmo/jsQR.git#1fb946a235abdc7709f04cd0e4aa316a3b6eae70",
|
||||
"prop-types": "15.6.0",
|
||||
"webrtc-adapter": "2.1.0"
|
||||
"webrtc-adapter": "5.0.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"sdp": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/sdp/-/sdp-2.6.0.tgz",
|
||||
"integrity": "sha512-/q5nUDSqvfh+P5pvb4Ez1IsF6F9aLLgslHrSDSltqvUuS7raTY9ROjbGJTyvGSYRs99FY59c8Od1lT7WVaiNAw=="
|
||||
},
|
||||
"webrtc-adapter": {
|
||||
"version": "5.0.6",
|
||||
"resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-5.0.6.tgz",
|
||||
"integrity": "sha512-dh2hPQFOPP0tLEYlFxtGI5vuQmRqkOdYni5wMKUHIx5I2dw0TJ1HdG7P+UechRWt6TvwPWhtbjVNQcQf1KXJmQ==",
|
||||
"requires": {
|
||||
"rtcpeerconnection-shim": "1.2.8",
|
||||
"sdp": "2.6.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-redux": {
|
||||
@@ -11221,6 +11237,21 @@
|
||||
"resolved": "https://registry.npmjs.org/rlp/-/rlp-2.0.0.tgz",
|
||||
"integrity": "sha1-nbOE/0uJqPYVY9kjldhiWxjzr7A="
|
||||
},
|
||||
"rtcpeerconnection-shim": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.8.tgz",
|
||||
"integrity": "sha512-5Sx90FGru1sQw9aGOM+kHU4i6mbP8eJPgxliu2X3Syhg8qgDybx8dpDTxUwfJvPnubXFnZeRNl59DWr4AttJKQ==",
|
||||
"requires": {
|
||||
"sdp": "2.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"sdp": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/sdp/-/sdp-2.6.0.tgz",
|
||||
"integrity": "sha512-/q5nUDSqvfh+P5pvb4Ez1IsF6F9aLLgslHrSDSltqvUuS7raTY9ROjbGJTyvGSYRs99FY59c8Od1lT7WVaiNAw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"rucksack-css": {
|
||||
"version": "0.9.1",
|
||||
"resolved": "https://registry.npmjs.org/rucksack-css/-/rucksack-css-0.9.1.tgz",
|
||||
@@ -11304,9 +11335,9 @@
|
||||
"integrity": "sha1-Jiw28CMc+nZU4jY/o5TNLexm83g="
|
||||
},
|
||||
"sdp": {
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/sdp/-/sdp-1.5.4.tgz",
|
||||
"integrity": "sha1-jgOPbdsUvXZa4fS1IW4SCUUR4NA="
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/sdp/-/sdp-2.6.0.tgz",
|
||||
"integrity": "sha512-/q5nUDSqvfh+P5pvb4Ez1IsF6F9aLLgslHrSDSltqvUuS7raTY9ROjbGJTyvGSYRs99FY59c8Od1lT7WVaiNAw=="
|
||||
},
|
||||
"secp256k1": {
|
||||
"version": "3.4.0",
|
||||
@@ -13171,11 +13202,12 @@
|
||||
}
|
||||
},
|
||||
"webrtc-adapter": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-2.1.0.tgz",
|
||||
"integrity": "sha1-YStbxs6Oc8nQZgA4oh+SVahnvz4=",
|
||||
"version": "5.0.6",
|
||||
"resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-5.0.6.tgz",
|
||||
"integrity": "sha512-dh2hPQFOPP0tLEYlFxtGI5vuQmRqkOdYni5wMKUHIx5I2dw0TJ1HdG7P+UechRWt6TvwPWhtbjVNQcQf1KXJmQ==",
|
||||
"requires": {
|
||||
"sdp": "1.5.4"
|
||||
"rtcpeerconnection-shim": "1.2.8",
|
||||
"sdp": "2.6.0"
|
||||
}
|
||||
},
|
||||
"websocket": {
|
||||
|
||||
@@ -179,7 +179,7 @@
|
||||
"react-intl": "2.1.5",
|
||||
"react-markdown": "2.4.4",
|
||||
"react-portal": "3.0.0",
|
||||
"react-qr-reader": "1.1.3",
|
||||
"react-qr-reader": "2.0.1",
|
||||
"react-redux": "4.4.6",
|
||||
"react-router": "3.0.0",
|
||||
"react-router-redux": "4.0.7",
|
||||
@@ -201,6 +201,7 @@
|
||||
"utf8": "2.1.2",
|
||||
"valid-url": "1.0.9",
|
||||
"validator": "6.2.0",
|
||||
"webrtc-adapter": "5.0.6",
|
||||
"whatwg-fetch": "2.0.1",
|
||||
"worker-loader": "^0.8.0",
|
||||
"zxcvbn": "4.4.1"
|
||||
|
||||
@@ -4,8 +4,9 @@ set -e
|
||||
# variables
|
||||
PVER="1-9"
|
||||
PTYPE="v1"
|
||||
TRACK="beta"
|
||||
UTCDATE=`date -u "+%Y%m%d-%H%M%S"`
|
||||
PRE_REPO="js-dist-paritytech/parity-${CI_BUILD_REF_NAME}-${PVER}-${PTYPE}.git"
|
||||
PRE_REPO="js-dist-paritytech/parity-${TRACK}-${PVER}-${PTYPE}.git"
|
||||
PRE_REPO_TOKEN="https://${GITHUB_JS_PRECOMPILED}:@github.com/${PRE_REPO}"
|
||||
BASEDIR=`dirname $0`
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
// test script 23
|
||||
// test script 25
|
||||
|
||||
@@ -4,4 +4,5 @@
|
||||
"author": "Parity <admin@parity.io>",
|
||||
"description": "Parity Wallet and Account management tools",
|
||||
"iconUrl": "icon.png",
|
||||
"allowJsEval": true
|
||||
}
|
||||
|
||||
@@ -306,7 +306,7 @@ export function fetchTokensBalances (updates, skipNotifications = false) {
|
||||
const tokenIdsToFetch = Object.values(balances)
|
||||
.reduce((tokenIds, balance) => {
|
||||
const nextTokenIds = Object.keys(balance)
|
||||
.filter((tokenId) => balance[tokenId].gt(0));
|
||||
.filter((tokenId) => balance[tokenId] && balance[tokenId].gt(0));
|
||||
|
||||
return tokenIds.concat(nextTokenIds);
|
||||
}, []);
|
||||
@@ -328,7 +328,7 @@ export function fetchTokensBalances (updates, skipNotifications = false) {
|
||||
dispatch(setBalances(balances, skipNotifications));
|
||||
})
|
||||
.catch((error) => {
|
||||
console.warn('balances::fetchTokensBalances', error);
|
||||
console.warn('v1: balances::fetchTokensBalances', error);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ export function loadTokens (options = {}) {
|
||||
}
|
||||
|
||||
export function loadTokensBasics (tokenIndexes, options) {
|
||||
const limit = 64;
|
||||
const limit = 128;
|
||||
|
||||
return (dispatch, getState) => {
|
||||
const { api } = getState();
|
||||
@@ -154,7 +154,7 @@ export function loadTokensBasics (tokenIndexes, options) {
|
||||
|
||||
export function fetchTokens (_tokenIndexes) {
|
||||
const tokenIndexes = uniq(_tokenIndexes || []);
|
||||
const tokenChunks = chunk(tokenIndexes, 64);
|
||||
const tokenChunks = chunk(tokenIndexes, 128);
|
||||
|
||||
return (dispatch, getState) => {
|
||||
const { tokenReg } = Contracts.get();
|
||||
|
||||
@@ -65,15 +65,15 @@ export default function (api, browserHistory, forEmbed = false) {
|
||||
.then(() => console.log('v1: started Status Provider'))
|
||||
|
||||
.then(() => console.log('v1: starting Personal Provider...'))
|
||||
.then(() => PersonalProvider.start())
|
||||
.then(() => withTimeoutForLight('personal', PersonalProvider.start(), store))
|
||||
.then(() => console.log('v1: started Personal Provider'))
|
||||
|
||||
.then(() => console.log('v1: starting Balances Provider...'))
|
||||
.then(() => BalancesProvider.start())
|
||||
.then(() => withTimeoutForLight('balances', BalancesProvider.start(), store))
|
||||
.then(() => console.log('v1: started Balances Provider'))
|
||||
|
||||
.then(() => console.log('v1: starting Tokens Provider...'))
|
||||
.then(() => TokensProvider.start())
|
||||
.then(() => withTimeoutForLight('tokens', TokensProvider.start(), store))
|
||||
.then(() => console.log('v1: started Tokens Provider'));
|
||||
};
|
||||
|
||||
@@ -97,3 +97,39 @@ export default function (api, browserHistory, forEmbed = false) {
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
function withTimeoutForLight (id, promise, store) {
|
||||
const { nodeKind } = store.getState().nodeStatus;
|
||||
const isLightNode = nodeKind.capability !== 'full';
|
||||
|
||||
if (!isLightNode) {
|
||||
// make sure that no values are passed
|
||||
return promise.then(() => {});
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let isResolved = false;
|
||||
const doResolve = () => {
|
||||
if (!isResolved) {
|
||||
isResolved = true;
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
const timeout = setTimeout(() => {
|
||||
console.warn(`Resolving ${id} by timeout.`);
|
||||
doResolve();
|
||||
}, 1000);
|
||||
|
||||
promise
|
||||
.then(() => {
|
||||
clearTimeout(timeout);
|
||||
doResolve();
|
||||
})
|
||||
.catch(err => {
|
||||
clearTimeout(timeout);
|
||||
if (!isResolved) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { range } from 'lodash';
|
||||
import { chunk, range } from 'lodash';
|
||||
import BigNumber from 'bignumber.js';
|
||||
|
||||
import { hashToImageUrl } from '~/redux/util';
|
||||
@@ -58,13 +58,11 @@ export function fetchTokensBasics (api, tokenReg, start = 0, limit = 100) {
|
||||
return decodeArray(api, 'address[]', result);
|
||||
})
|
||||
.then((tokenAddresses) => {
|
||||
return tokenAddresses.map((tokenAddress, index) => {
|
||||
return tokenAddresses.map((address, index) => {
|
||||
const tokenIndex = start + index;
|
||||
|
||||
return {
|
||||
address: /^0x0*$/.test(tokenAddress)
|
||||
? ''
|
||||
: tokenAddress,
|
||||
address,
|
||||
id: getTokenId(tokenIndex),
|
||||
index: tokenIndex,
|
||||
fetched: false
|
||||
@@ -80,12 +78,17 @@ export function fetchTokensBasics (api, tokenReg, start = 0, limit = 100) {
|
||||
|
||||
return tokens.map((token) => {
|
||||
if (balances[token.id] && balances[token.id].gt(0)) {
|
||||
token.address = '';
|
||||
token.address = null;
|
||||
}
|
||||
|
||||
return token;
|
||||
});
|
||||
});
|
||||
})
|
||||
.then((tokens) => {
|
||||
return tokens.filter(({ address }) => {
|
||||
return address && !/^0x0*$/.test(address);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -195,19 +198,22 @@ export function fetchAccountsBalances (api, tokens, updates) {
|
||||
});
|
||||
|
||||
const tokenPromise = Object.keys(tokenUpdates)
|
||||
.reduce((tokenPromise, accountAddress) => {
|
||||
.reduce((promises, accountAddress) => {
|
||||
const tokenIds = tokenUpdates[accountAddress];
|
||||
const updateTokens = tokens
|
||||
.filter((t) => tokenIds.includes(t.id));
|
||||
|
||||
return tokenPromise
|
||||
.then(() => fetchTokensBalances(api, updateTokens, [ accountAddress ]))
|
||||
.then((balances) => {
|
||||
tokensBalances[accountAddress] = balances[accountAddress];
|
||||
});
|
||||
}, Promise.resolve());
|
||||
promises.push(
|
||||
fetchTokensBalances(api, updateTokens, [ accountAddress ])
|
||||
.then((balances) => {
|
||||
tokensBalances[accountAddress] = balances[accountAddress];
|
||||
})
|
||||
);
|
||||
|
||||
return Promise.all([ ethPromise, tokenPromise ])
|
||||
return promises;
|
||||
}, []);
|
||||
|
||||
return Promise.all([ ethPromise, Promise.all(tokenPromise) ])
|
||||
.then(() => {
|
||||
const balances = Object.assign({}, tokensBalances);
|
||||
|
||||
@@ -243,29 +249,24 @@ function fetchEthBalances (api, accountAddresses) {
|
||||
});
|
||||
}
|
||||
|
||||
function fetchTokensBalances (api, tokens, accountAddresses) {
|
||||
const tokenAddresses = tokens.map((t) => t.address);
|
||||
const tokensBalancesCallData = encode(
|
||||
api,
|
||||
[ 'address[]', 'address[]' ],
|
||||
[ accountAddresses, tokenAddresses ]
|
||||
);
|
||||
function fetchTokensBalances (api, _tokens, accountAddresses) {
|
||||
const promises = chunk(_tokens, 128).map((tokens) => {
|
||||
const data = tokensBalancesBytecode + encode(
|
||||
api,
|
||||
[ 'address[]', 'address[]' ],
|
||||
[ accountAddresses, tokens.map(({ address }) => address) ]
|
||||
);
|
||||
|
||||
return api.eth
|
||||
.call({ data: tokensBalancesBytecode + tokensBalancesCallData })
|
||||
.then((result) => {
|
||||
const rawBalances = decodeArray(api, 'uint[]', result);
|
||||
return api.eth.call({ data }).then((result) => {
|
||||
const balances = {};
|
||||
const rawBalances = decodeArray(api, 'uint[]', result);
|
||||
|
||||
accountAddresses.forEach((accountAddress, accountIndex) => {
|
||||
const preIndex = accountIndex * tokens.length;
|
||||
const balance = {};
|
||||
const preIndex = accountIndex * tokenAddresses.length;
|
||||
|
||||
tokenAddresses.forEach((tokenAddress, tokenIndex) => {
|
||||
const index = preIndex + tokenIndex;
|
||||
const token = tokens[tokenIndex];
|
||||
|
||||
balance[token.id] = rawBalances[index];
|
||||
tokens.forEach((token, tokenIndex) => {
|
||||
balance[token.id] = rawBalances[preIndex + tokenIndex];
|
||||
});
|
||||
|
||||
balances[accountAddress] = balance;
|
||||
@@ -273,6 +274,31 @@ function fetchTokensBalances (api, tokens, accountAddresses) {
|
||||
|
||||
return balances;
|
||||
});
|
||||
});
|
||||
|
||||
return Promise.all(promises).then((results) => {
|
||||
return results.reduce((combined, result) => {
|
||||
Object
|
||||
.keys(result)
|
||||
.forEach((address) => {
|
||||
if (!combined[address]) {
|
||||
combined[address] = {};
|
||||
}
|
||||
|
||||
Object
|
||||
.keys(result[address])
|
||||
.forEach((token) => {
|
||||
const value = result[address][token];
|
||||
|
||||
if (value && value.gt(0)) {
|
||||
combined[address][token] = result[address][token];
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return combined;
|
||||
}, {});
|
||||
});
|
||||
}
|
||||
|
||||
function getTokenId (...args) {
|
||||
|
||||
1683
js/package-lock.json
generated
@@ -44,17 +44,17 @@
|
||||
"test:coverage": "cross-env NODE_ENV=test istanbul cover _mocha -- 'src/**/*.spec.js'"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@parity/dapp-console": "paritytech/dapp-console",
|
||||
"@parity/dapp-console": "parity-js/dapp-console#5562e6c11783dc82c1ee37fd85dc3403ff28f8f5",
|
||||
"@parity/dapp-dapp-methods": "js-dist-paritytech/dapp-dapp-methods",
|
||||
"@parity/dapp-dapp-visible": "js-dist-paritytech/dapp-dapp-visible",
|
||||
"@parity/dapp-dappreg": "paritytech/dapp-dappreg",
|
||||
"@parity/dapp-githubhint": "paritytech/dapp-githubhint",
|
||||
"@parity/dapp-localtx": "paritytech/dapp-localtx",
|
||||
"@parity/dapp-registry": "paritytech/dapp-registry",
|
||||
"@parity/dapp-signaturereg": "paritytech/dapp-signaturereg",
|
||||
"@parity/dapp-dappreg": "parity-js/dapp-dappreg#66f2e52dfa9a783cc0ca616505460e5e34ebdf54",
|
||||
"@parity/dapp-githubhint": "parity-js/dapp-githubhint#b5cdef016e8bead7669ca077be526897ee42f83a",
|
||||
"@parity/dapp-localtx": "parity-js/dapp-localtx#ac1d82c7f55bf0b6e2bf0e56044f95fa49c52ea9",
|
||||
"@parity/dapp-registry": "parity-js/dapp-registry#d3aeab6437ebcc5537e5f71a1cd49c8de8329f34",
|
||||
"@parity/dapp-signaturereg": "parity-js/dapp-signaturereg#f597e976bd89b07809173d7a35e3929ac81e7e75",
|
||||
"@parity/dapp-status": "js-dist-paritytech/dapp-status",
|
||||
"@parity/dapp-tokendeploy": "paritytech/dapp-tokendeploy",
|
||||
"@parity/dapp-tokenreg": "paritytech/dapp-tokenreg",
|
||||
"@parity/dapp-tokendeploy": "parity-js/dapp-tokendeploy#0f6f9f2adb82c02e35056dba792a75e95f440cdd",
|
||||
"@parity/dapp-tokenreg": "parity-js/dapp-tokenreg#9750a2c10a934f9ae0e6e7fd6fa5b9e25a7b0785",
|
||||
"babel-cli": "6.26.0",
|
||||
"babel-core": "6.26.0",
|
||||
"babel-eslint": "7.1.1",
|
||||
@@ -141,12 +141,12 @@
|
||||
"yargs": "6.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@parity/api": "^2.1.14",
|
||||
"@parity/plugin-signer-account": "paritytech/plugin-signer-account",
|
||||
"@parity/plugin-signer-default": "paritytech/plugin-signer-default",
|
||||
"@parity/plugin-signer-hardware": "paritytech/plugin-signer-hardware",
|
||||
"@parity/plugin-signer-qr": "paritytech/plugin-signer-qr",
|
||||
"@parity/shared": "2.2.21",
|
||||
"@parity/api": "2.1.15",
|
||||
"@parity/plugin-signer-account": "parity-js/plugin-signer-account#c1272caa242c8b97dac78e5d0b1e068614657fdc",
|
||||
"@parity/plugin-signer-default": "parity-js/plugin-signer-default#9a47bded9d6d70b69bb2f719732bd6f7854d1842",
|
||||
"@parity/plugin-signer-hardware": "parity-js/plugin-signer-hardware#4320d818a053d4efae890b74a7476e4c8dc6ba10",
|
||||
"@parity/plugin-signer-qr": "parity-js/plugin-signer-qr#2d1fafad347ba53eaf58c14265d4d07631d6a45c",
|
||||
"@parity/shared": "2.2.23",
|
||||
"@parity/ui": "3.0.22",
|
||||
"keythereum": "1.0.2",
|
||||
"lodash.flatten": "4.4.0",
|
||||
@@ -170,7 +170,6 @@
|
||||
"redux": "3.7.2",
|
||||
"semantic-ui-react": "0.77.0",
|
||||
"solc": "ngotchac/solc-js",
|
||||
"store": "1.3.20",
|
||||
"web3": "1.0.0-beta.26"
|
||||
"store": "1.3.20"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ set -e
|
||||
# variables
|
||||
PVER="1-9"
|
||||
UTCDATE=`date -u "+%Y%m%d-%H%M%S"`
|
||||
BRANCH=$CI_BUILD_REF_NAME
|
||||
BRANCH="beta"
|
||||
GIT_PARITY="https://${GITHUB_JS_PRECOMPILED}:@github.com/paritytech/parity.git"
|
||||
|
||||
echo "*** [cargo] Setting up GitHub config for parity"
|
||||
|
||||
@@ -4,8 +4,9 @@ set -e
|
||||
# variables
|
||||
PVER="1-9"
|
||||
PTYPE="shell"
|
||||
TRACK="beta"
|
||||
UTCDATE=`date -u "+%Y%m%d-%H%M%S"`
|
||||
PRE_REPO="js-dist-paritytech/parity-${CI_BUILD_REF_NAME}-${PVER}-${PTYPE}.git"
|
||||
PRE_REPO="js-dist-paritytech/parity-${TRACK}-${PVER}-${PTYPE}.git"
|
||||
PRE_REPO_TOKEN="https://${GITHUB_JS_PRECOMPILED}:@github.com/${PRE_REPO}"
|
||||
BASEDIR=`dirname $0`
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
// test script 29
|
||||
// test script 31
|
||||
|
||||
@@ -135,6 +135,7 @@ export default class Dapp extends Component {
|
||||
|
||||
return (
|
||||
<iframe
|
||||
allow='camera'
|
||||
className={ styles.frame }
|
||||
frameBorder={ 0 }
|
||||
id='dappFrame'
|
||||
|
||||
@@ -26,11 +26,14 @@
|
||||
.list {
|
||||
margin: 0 !important;
|
||||
padding: 1em 1em !important;
|
||||
background-color: #f5f5f5;
|
||||
background-color: white;
|
||||
|
||||
}
|
||||
|
||||
.isDefault {
|
||||
background-color: white;
|
||||
.accountsList {
|
||||
background-color: #f5f5f5;
|
||||
height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.hasOtherAccounts {
|
||||
|
||||
@@ -68,14 +68,14 @@ class DefaultAccount extends Component {
|
||||
}
|
||||
content={
|
||||
<div>
|
||||
<List relaxed='very' selection className={ [styles.list, styles.isDefault, allAccounts.length > 1 && styles.hasOtherAccounts].join(' ') }>
|
||||
<List relaxed='very' selection className={ [styles.list, allAccounts.length > 1 && styles.hasOtherAccounts].join(' ') }>
|
||||
<AccountItem
|
||||
isDefault
|
||||
account={ defaultAccount }
|
||||
/>
|
||||
</List>
|
||||
{allAccounts.length > 1 &&
|
||||
<List relaxed='very' selection className={ styles.list } divided>
|
||||
<List relaxed='very' selection className={ [styles.list, styles.accountsList].join(' ') } divided>
|
||||
{allAccounts
|
||||
.filter(({ address }) => address !== defaultAddress)
|
||||
.map(account => (
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
import Api from '@parity/api';
|
||||
import qs from 'query-string';
|
||||
import Web3 from 'web3';
|
||||
|
||||
function initProvider () {
|
||||
const path = window.location.pathname.split('/');
|
||||
@@ -48,24 +47,9 @@ function initProvider () {
|
||||
}
|
||||
|
||||
function initWeb3 (ethereum) {
|
||||
// FIXME: Use standard provider for web3
|
||||
const provider = new Api.Provider.SendAsync(ethereum);
|
||||
const web3 = new Web3(provider);
|
||||
const currentProvider = new Api.Provider.SendAsync(ethereum);
|
||||
|
||||
if (!web3.currentProvider) {
|
||||
web3.currentProvider = provider;
|
||||
}
|
||||
|
||||
// set default account
|
||||
web3.eth.getAccounts((error, accounts) => {
|
||||
if (error || !accounts || !accounts[0]) {
|
||||
return;
|
||||
}
|
||||
|
||||
web3.eth.defaultAccount = accounts[0];
|
||||
});
|
||||
|
||||
window.web3 = web3;
|
||||
window.web3 = { currentProvider };
|
||||
}
|
||||
|
||||
function initParity (ethereum) {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
//! Ethash params deserialization.
|
||||
|
||||
use uint::Uint;
|
||||
use uint::{self, Uint};
|
||||
use hash::Address;
|
||||
|
||||
/// Deserializable doppelganger of EthashParams.
|
||||
@@ -27,12 +27,15 @@ pub struct EthashParams {
|
||||
pub minimum_difficulty: Uint,
|
||||
/// See main EthashParams docs.
|
||||
#[serde(rename="difficultyBoundDivisor")]
|
||||
#[serde(deserialize_with="uint::validate_non_zero")]
|
||||
pub difficulty_bound_divisor: Uint,
|
||||
/// See main EthashParams docs.
|
||||
#[serde(rename="difficultyIncrementDivisor")]
|
||||
#[serde(default, deserialize_with="uint::validate_optional_non_zero")]
|
||||
pub difficulty_increment_divisor: Option<Uint>,
|
||||
/// See main EthashParams docs.
|
||||
#[serde(rename="metropolisDifficultyIncrementDivisor")]
|
||||
#[serde(default, deserialize_with="uint::validate_optional_non_zero")]
|
||||
pub metropolis_difficulty_increment_divisor: Option<Uint>,
|
||||
/// See main EthashParams docs.
|
||||
#[serde(rename="durationLimit")]
|
||||
@@ -60,6 +63,7 @@ pub struct EthashParams {
|
||||
pub difficulty_hardfork_transition: Option<Uint>,
|
||||
/// See main EthashParams docs.
|
||||
#[serde(rename="difficultyHardforkBoundDivisor")]
|
||||
#[serde(default, deserialize_with="uint::validate_optional_non_zero")]
|
||||
pub difficulty_hardfork_bound_divisor: Option<Uint>,
|
||||
/// See main EthashParams docs.
|
||||
#[serde(rename="bombDefuseTransition")]
|
||||
@@ -302,4 +306,17 @@ mod tests {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "a non-zero value")]
|
||||
fn test_zero_value_divisor() {
|
||||
let s = r#"{
|
||||
"params": {
|
||||
"difficultyBoundDivisor": "0x0",
|
||||
"minimumDifficulty": "0x020000"
|
||||
}
|
||||
}"#;
|
||||
|
||||
let _deserialized: Ethash = serde_json::from_str(s).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
//! Spec params deserialization.
|
||||
|
||||
use uint::Uint;
|
||||
use uint::{self, Uint};
|
||||
use hash::{H256, Address};
|
||||
use bytes::Bytes;
|
||||
|
||||
@@ -98,10 +98,9 @@ pub struct Params {
|
||||
pub nonce_cap_increment: Option<Uint>,
|
||||
/// See `CommonParams` docs.
|
||||
pub remove_dust_contracts : Option<bool>,
|
||||
/// Wasm support flag
|
||||
pub wasm: Option<bool>,
|
||||
/// See `CommonParams` docs.
|
||||
#[serde(rename="gasLimitBoundDivisor")]
|
||||
#[serde(deserialize_with="uint::validate_non_zero")]
|
||||
pub gas_limit_bound_divisor: Uint,
|
||||
/// See `CommonParams` docs.
|
||||
pub registrar: Option<Address>,
|
||||
@@ -117,6 +116,9 @@ pub struct Params {
|
||||
/// Transaction permission contract address.
|
||||
#[serde(rename="transactionPermissionContract")]
|
||||
pub transaction_permission_contract: Option<Address>,
|
||||
/// Wasm activation block height, if not activated from start
|
||||
#[serde(rename="wasmActivationTransition")]
|
||||
pub wasm_activation_transition: Option<Uint>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -136,7 +138,8 @@ mod tests {
|
||||
"minGasLimit": "0x1388",
|
||||
"accountStartNonce": "0x01",
|
||||
"gasLimitBoundDivisor": "0x20",
|
||||
"maxCodeSize": "0x1000"
|
||||
"maxCodeSize": "0x1000",
|
||||
"wasmActivationTransition": "0x1010"
|
||||
}"#;
|
||||
|
||||
let deserialized: Params = serde_json::from_str(s).unwrap();
|
||||
@@ -148,5 +151,23 @@ mod tests {
|
||||
assert_eq!(deserialized.account_start_nonce, Some(Uint(U256::from(0x01))));
|
||||
assert_eq!(deserialized.gas_limit_bound_divisor, Uint(U256::from(0x20)));
|
||||
assert_eq!(deserialized.max_code_size, Some(Uint(U256::from(0x1000))));
|
||||
assert_eq!(deserialized.wasm_activation_transition, Some(Uint(U256::from(0x1010))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "a non-zero value")]
|
||||
fn test_zero_value_divisor() {
|
||||
let s = r#"{
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"networkID" : "0x1",
|
||||
"chainID" : "0x15",
|
||||
"subprotocolName" : "exp",
|
||||
"minGasLimit": "0x1388",
|
||||
"accountStartNonce": "0x01",
|
||||
"gasLimitBoundDivisor": "0x0",
|
||||
"maxCodeSize": "0x1000"
|
||||
}"#;
|
||||
|
||||
let _deserialized: Params = serde_json::from_str(s).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use serde::de::{Error, Visitor};
|
||||
use serde::de::{Error, Visitor, Unexpected};
|
||||
use bigint::prelude::U256;
|
||||
|
||||
/// Lenient uint json deserialization for test json files.
|
||||
@@ -90,6 +90,28 @@ impl<'a> Visitor<'a> for UintVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate_non_zero<'de, D>(d: D) -> Result<Uint, D::Error> where D: Deserializer<'de> {
|
||||
let value = Uint::deserialize(d)?;
|
||||
|
||||
if value == Uint(U256::from(0)) {
|
||||
return Err(Error::invalid_value(Unexpected::Unsigned(value.into()), &"a non-zero value"))
|
||||
}
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
pub fn validate_optional_non_zero<'de, D>(d: D) -> Result<Option<Uint>, D::Error> where D: Deserializer<'de> {
|
||||
let value: Option<Uint> = Option::deserialize(d)?;
|
||||
|
||||
if let Some(value) = value {
|
||||
if value == Uint(U256::from(0)) {
|
||||
return Err(Error::invalid_value(Unexpected::Unsigned(value.into()), &"a non-zero value"))
|
||||
}
|
||||
}
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use serde_json;
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
0ACF9AC71E30FAB600D5C935 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0ACF9AC51E30FAB600D5C935 /* MainMenu.xib */; };
|
||||
0AE564F11E3CE42C00BD01F7 /* GetBSDProcessList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE564F01E3CE42C00BD01F7 /* GetBSDProcessList.swift */; };
|
||||
0AED4DA01E3E22F800BF87C0 /* ethstore in CopyFiles */ = {isa = PBXBuildFile; fileRef = 0AED4D9F1E3E22F800BF87C0 /* ethstore */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
84CF92B3200E559900AD6E78 /* parity-evm in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84CF92B2200E559900AD6E78 /* parity-evm */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
84CF92B6200E56AE00AD6E78 /* ethkey in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84CF92B5200E56AE00AD6E78 /* ethkey */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@@ -22,6 +24,8 @@
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 6;
|
||||
files = (
|
||||
84CF92B6200E56AE00AD6E78 /* ethkey in CopyFiles */,
|
||||
84CF92B3200E559900AD6E78 /* parity-evm in CopyFiles */,
|
||||
0AED4DA01E3E22F800BF87C0 /* ethstore in CopyFiles */,
|
||||
0A7A475D1E3D2CDD0093D1AB /* parity in CopyFiles */,
|
||||
);
|
||||
@@ -38,6 +42,8 @@
|
||||
0ACF9AC81E30FAB600D5C935 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
0AE564F01E3CE42C00BD01F7 /* GetBSDProcessList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetBSDProcessList.swift; sourceTree = "<group>"; };
|
||||
0AED4D9F1E3E22F800BF87C0 /* ethstore */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = ethstore; path = ../target/release/ethstore; sourceTree = "<group>"; };
|
||||
84CF92B2200E559900AD6E78 /* parity-evm */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = "parity-evm"; path = "../target/release/parity-evm"; sourceTree = "<group>"; };
|
||||
84CF92B5200E56AE00AD6E78 /* ethkey */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = ethkey; path = ../target/release/ethkey; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -54,6 +60,8 @@
|
||||
0ACF9AB51E30FAB600D5C935 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84CF92B5200E56AE00AD6E78 /* ethkey */,
|
||||
84CF92B2200E559900AD6E78 /* parity-evm */,
|
||||
0AED4D9F1E3E22F800BF87C0 /* ethstore */,
|
||||
0A7A475C1E3D2CDD0093D1AB /* parity */,
|
||||
0ACF9AC01E30FAB600D5C935 /* Parity Ethereum */,
|
||||
@@ -110,7 +118,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0800;
|
||||
LastUpgradeCheck = 0800;
|
||||
LastUpgradeCheck = 0820;
|
||||
ORGANIZATIONNAME = "Parity Technologies";
|
||||
TargetAttributes = {
|
||||
0ACF9ABD1E30FAB600D5C935 = {
|
||||
@@ -192,6 +200,7 @@
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
@@ -241,6 +250,7 @@
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
|
||||
@@ -462,7 +462,7 @@
|
||||
<key>OVERWRITE_PERMISSIONS</key>
|
||||
<false/>
|
||||
<key>VERSION</key>
|
||||
<string>1.9.0</string>
|
||||
<string>1.9.3</string>
|
||||
</dict>
|
||||
<key>UUID</key>
|
||||
<string>2DCD5B81-7BAF-4DA1-9251-6274B089FD36</string>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
@@ -22,12 +22,12 @@ import Cocoa
|
||||
class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
@IBOutlet weak var statusMenu: NSMenu!
|
||||
@IBOutlet weak var startAtLogonMenuItem: NSMenuItem!
|
||||
|
||||
|
||||
let statusItem = NSStatusBar.system().statusItem(withLength: NSVariableStatusItemLength)
|
||||
var parityPid: Int32? = nil
|
||||
var commandLine: [String] = []
|
||||
let defaultDefaults = "{\"fat_db\":false,\"mode\":\"passive\",\"mode.alarm\":3600,\"mode.timeout\":300,\"pruning\":\"fast\",\"tracing\":false}"
|
||||
|
||||
|
||||
func menuAppPath() -> String {
|
||||
return Bundle.main.executablePath!
|
||||
}
|
||||
@@ -40,20 +40,20 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
return NSRunningApplication.runningApplications(withBundleIdentifier: Bundle.main.bundleIdentifier!).count > 1
|
||||
|
||||
}
|
||||
|
||||
|
||||
func isParityRunning() -> Bool {
|
||||
if let pid = self.parityPid {
|
||||
return kill(pid, 0) == 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
func killParity() {
|
||||
if let pid = self.parityPid {
|
||||
kill(pid, SIGKILL)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func openUI() {
|
||||
let parity = Process()
|
||||
parity.launchPath = self.parityPath()
|
||||
@@ -61,29 +61,29 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
parity.arguments!.append("ui")
|
||||
parity.launch()
|
||||
}
|
||||
|
||||
|
||||
func writeConfigFiles() {
|
||||
let basePath = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first?
|
||||
.appendingPathComponent(Bundle.main.bundleIdentifier!, isDirectory: true)
|
||||
|
||||
|
||||
if FileManager.default.fileExists(atPath: basePath!.path) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
let defaultsFileDir = basePath?.appendingPathComponent("chains").appendingPathComponent("ethereum")
|
||||
let defaultsFile = defaultsFileDir?.appendingPathComponent("user_defaults")
|
||||
|
||||
|
||||
try FileManager.default.createDirectory(atPath: (defaultsFileDir?.path)!, withIntermediateDirectories: true, attributes: nil)
|
||||
if !FileManager.default.fileExists(atPath: defaultsFile!.path) {
|
||||
try defaultDefaults.write(to: defaultsFile!, atomically: false, encoding: String.Encoding.utf8)
|
||||
}
|
||||
|
||||
|
||||
let configFile = basePath?.appendingPathComponent("config.toml")
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
|
||||
|
||||
func autostartEnabled() -> Bool {
|
||||
return itemReferencesInLoginItems().existingReference != nil
|
||||
}
|
||||
@@ -123,7 +123,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
}
|
||||
return (nil, nil)
|
||||
}
|
||||
|
||||
|
||||
func toggleLaunchAtStartup() {
|
||||
let itemReferences = itemReferencesInLoginItems()
|
||||
let shouldBeToggled = (itemReferences.existingReference == nil)
|
||||
@@ -155,7 +155,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
|
||||
func launchParity() {
|
||||
self.commandLine = CommandLine.arguments.dropFirst().filter({ $0 != "ui"})
|
||||
|
||||
|
||||
let processes = GetBSDProcessList()!
|
||||
let parityProcess = processes.index(where: {
|
||||
var name = $0.kp_proc.p_comm
|
||||
@@ -166,7 +166,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
}
|
||||
return str == "parity"
|
||||
})
|
||||
|
||||
|
||||
if parityProcess == nil {
|
||||
let parity = Process()
|
||||
let p = self.parityPath()
|
||||
@@ -178,7 +178,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
self.parityPid = processes[parityProcess!].kp_proc.p_pid
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
||||
if self.isAlreadyRunning() {
|
||||
openUI()
|
||||
@@ -188,12 +188,12 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
|
||||
self.writeConfigFiles()
|
||||
self.launchParity()
|
||||
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: {_ in
|
||||
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: {_ in
|
||||
if !self.isParityRunning() {
|
||||
NSApplication.shared().terminate(self)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
let icon = NSImage(named: "statusIcon")
|
||||
icon?.isTemplate = true // best for dark mode
|
||||
statusItem.image = icon
|
||||
@@ -206,19 +206,18 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@IBAction func quitClicked(_ sender: NSMenuItem) {
|
||||
self.killParity()
|
||||
NSApplication.shared().terminate(self)
|
||||
}
|
||||
|
||||
|
||||
@IBAction func openClicked(_ sender: NSMenuItem) {
|
||||
self.openUI()
|
||||
}
|
||||
|
||||
|
||||
@IBAction func startAtLogonClicked(_ sender: NSMenuItem) {
|
||||
self.toggleLaunchAtStartup()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 372 B After Width: | Height: | Size: 679 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 707 B After Width: | Height: | Size: 1.7 KiB |
@@ -1,4 +1,4 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
@@ -21,21 +21,21 @@ import Foundation
|
||||
import Darwin
|
||||
|
||||
public func GetBSDProcessList() -> ([kinfo_proc]?) {
|
||||
|
||||
|
||||
var done = false
|
||||
var result: [kinfo_proc]?
|
||||
var err: Int32
|
||||
|
||||
|
||||
repeat {
|
||||
let name = [CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0];
|
||||
let namePointer = name.withUnsafeBufferPointer { UnsafeMutablePointer<Int32>(mutating: $0.baseAddress) }
|
||||
var length: Int = 0
|
||||
|
||||
|
||||
err = sysctl(namePointer, u_int(name.count), nil, &length, nil, 0)
|
||||
if err == -1 {
|
||||
err = errno
|
||||
}
|
||||
|
||||
|
||||
if err == 0 {
|
||||
let count = length / MemoryLayout<kinfo_proc>.stride
|
||||
result = [kinfo_proc](repeating: kinfo_proc(), count: count)
|
||||
@@ -54,6 +54,6 @@ public func GetBSDProcessList() -> ([kinfo_proc]?) {
|
||||
}
|
||||
}
|
||||
} while err == 0 && !done
|
||||
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@ Parity Wallet
|
||||
|
||||
Welcome to Parity Wallet, your all-in-one Ethereum node and wallet.
|
||||
|
||||
WARNING: This installer is **EXPERIMENTAL**. Use it at your own risk.
|
||||
|
||||
If you continue, Parity will be installed as a user service. You will be able to use the Parity Wallet through your browser by using the menu bar icon, following the shortcut in the Launchpad or navigating to http://localhost:8080/ in your browser.
|
||||
If you continue, Parity will be installed as a user service. You will be able to use the Parity Wallet through your browser by using the menu bar icon, following the shortcut in the Launchpad or navigating to http://localhost:8180/ in your browser.
|
||||
|
||||
Parity is distributed under the terms of the GPL.
|
||||
|
||||
@@ -9,5 +9,4 @@ fi
|
||||
PLIST=~/Library/LaunchAgents/io.parity.ethereum.plist
|
||||
su $SUDO_USER -c "launchctl stop io.parity.ethereum"
|
||||
su $SUDO_USER -c "launchctl unload $PLIST"
|
||||
rm -f /usr/local/libexec/parity /usr/local/libexec/uninstall-parity.sh /usr/local/bin/ethstore $PLIST
|
||||
|
||||
rm -f /usr/local/libexec/parity /usr/local/libexec/uninstall-parity.sh /usr/local/bin/ethstore /usr/local/bin/ethkey /usr/local/bin/parity-evm $PLIST
|
||||
|
||||
@@ -6,17 +6,17 @@
|
||||
!define SYNC_TERM 0x00100001
|
||||
|
||||
!define APPNAME "Parity"
|
||||
!define COMPANYNAME "Parity"
|
||||
!define COMPANYNAME "Parity Technologies"
|
||||
!define DESCRIPTION "Fast, light, robust Ethereum implementation"
|
||||
!define VERSIONMAJOR 1
|
||||
!define VERSIONMINOR 9
|
||||
!define VERSIONBUILD 0
|
||||
!define VERSIONBUILD 3
|
||||
!define ARGS ""
|
||||
!define FIRST_START_ARGS "--mode=passive ui"
|
||||
|
||||
!addplugindir .\
|
||||
|
||||
!define HELPURL "https://github.com/paritytech/parity/wiki" # "Support Information" link
|
||||
!define HELPURL "https://paritytech.github.io/wiki/" # "Support Information" link
|
||||
!define UPDATEURL "https://github.com/paritytech/parity/releases" # "Product Updates" link
|
||||
!define ABOUTURL "https://github.com/paritytech/parity" # "Publisher" link
|
||||
!define INSTALLSIZE 26120
|
||||
@@ -88,14 +88,13 @@ section "install"
|
||||
!insertmacro TerminateApp
|
||||
|
||||
# Files added here should be removed by the uninstaller (see section "uninstall")
|
||||
file /oname=parity.exe ..\target\release\parity.exe
|
||||
file /oname=parity.exe ..\target\x86_64-pc-windows-msvc\release\parity.exe
|
||||
file /oname=parity-evm.exe ..\target\x86_64-pc-windows-msvc\release\parity-evm.exe
|
||||
file /oname=ethstore.exe ..\target\x86_64-pc-windows-msvc\release\ethstore.exe
|
||||
file /oname=ethkey.exe ..\target\x86_64-pc-windows-msvc\release\ethkey.exe
|
||||
file /oname=ptray.exe ..\windows\ptray\x64\Release\ptray.exe
|
||||
|
||||
file "logo.ico"
|
||||
file vc_redist.x64.exe
|
||||
|
||||
ExecWait '"$INSTDIR\vc_redist.x64.exe" /passive /norestart'
|
||||
delete $INSTDIR\vc_redist.x64.exe
|
||||
# Add any other files for the install directory (license files, app data, etc) here
|
||||
|
||||
# Uninstaller - See function un.onInit and section "uninstall" for configuration
|
||||
@@ -167,6 +166,9 @@ section "uninstall"
|
||||
|
||||
# Remove files
|
||||
delete $INSTDIR\parity.exe
|
||||
delete $INSTDIR\parity-evm.exe
|
||||
delete $INSTDIR\ethstore.exe
|
||||
delete $INSTDIR\ethkey.exe
|
||||
delete $INSTDIR\ptray.exe
|
||||
delete $INSTDIR\logo.ico
|
||||
|
||||
@@ -187,4 +189,3 @@ section "uninstall"
|
||||
DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "${APPNAME}"
|
||||
DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "${APPNAME}"
|
||||
sectionEnd
|
||||
|
||||
|
||||
@@ -257,12 +257,7 @@ usage! {
|
||||
|
||||
ARG arg_mode: (String) = "last", or |c: &Config| otry!(c.parity).mode.clone(),
|
||||
"--mode=[MODE]",
|
||||
"Set the operating mode. MODE can be one of:
|
||||
last - Uses the last-used mode, active if none.
|
||||
active - Parity continuously syncs the chain.
|
||||
passive - Parity syncs initially, then sleeps and wakes regularly to resync.
|
||||
dark - Parity syncs only when the RPC is active.
|
||||
offline - Parity doesn't sync.",
|
||||
"Set the operating mode. MODE can be one of: last - Uses the last-used mode, active if none; active - Parity continuously syncs the chain; passive - Parity syncs initially, then sleeps and wakes regularly to resync; dark - Parity syncs only when the RPC is active; offline - Parity doesn't sync.",
|
||||
|
||||
ARG arg_mode_timeout: (u64) = 300u64, or |c: &Config| otry!(c.parity).mode_timeout.clone(),
|
||||
"--mode-timeout=[SECS]",
|
||||
@@ -274,19 +269,11 @@ usage! {
|
||||
|
||||
ARG arg_auto_update: (String) = "critical", or |c: &Config| otry!(c.parity).auto_update.clone(),
|
||||
"--auto-update=[SET]",
|
||||
"Set a releases set to automatically update and install.
|
||||
all - All updates in the our release track.
|
||||
critical - Only consensus/security updates.
|
||||
none - No updates will be auto-installed.",
|
||||
"Set a releases set to automatically update and install. SET can be one of: all - All updates in the our release track; critical - Only consensus/security updates; none - No updates will be auto-installed.",
|
||||
|
||||
ARG arg_release_track: (String) = "current", or |c: &Config| otry!(c.parity).release_track.clone(),
|
||||
"--release-track=[TRACK]",
|
||||
"Set which release track we should use for updates.
|
||||
stable - Stable releases.
|
||||
beta - Beta releases.
|
||||
nightly - Nightly releases (unstable).
|
||||
testing - Testing releases (do not use).
|
||||
current - Whatever track this executable was released on",
|
||||
"Set which release track we should use for updates. TRACK can be one of: stable - Stable releases; beta - Beta releases; nightly - Nightly releases (unstable); testing - Testing releases (do not use); current - Whatever track this executable was released on.",
|
||||
|
||||
ARG arg_chain: (String) = "foundation", or |c: &Config| otry!(c.parity).chain.clone(),
|
||||
"--chain=[CHAIN]",
|
||||
@@ -311,8 +298,7 @@ usage! {
|
||||
["Convenience options"]
|
||||
FLAG flag_unsafe_expose: (bool) = false, or |c: &Config| otry!(c.misc).unsafe_expose,
|
||||
"--unsafe-expose",
|
||||
"All servers will listen on external interfaces and will be remotely accessible. It's equivalent with setting the following: --{{ws,jsonrpc,ui,ipfs,secret_store,stratum}}-interface=all --*-hosts=all
|
||||
This option is UNSAFE and should be used with great care!",
|
||||
"All servers will listen on external interfaces and will be remotely accessible. It's equivalent with setting the following: --{{ws,jsonrpc,ui,ipfs,secret_store,stratum}}-interface=all --*-hosts=all This option is UNSAFE and should be used with great care!",
|
||||
|
||||
ARG arg_config: (String) = "$BASE/config.toml", or |_| None,
|
||||
"-c, --config=[CONFIG]",
|
||||
@@ -498,7 +484,7 @@ usage! {
|
||||
|
||||
ARG arg_ws_hosts: (String) = "none", or |c: &Config| otry!(c.websockets).hosts.as_ref().map(|vec| vec.join(",")),
|
||||
"--ws-hosts=[HOSTS]",
|
||||
"List of allowed Host header values. This option will validate the Host header sent by the browser, it is additional security against some attack vectors. Special options: \"all\", \"none\",.",
|
||||
"List of allowed Host header values. This option will validate the Host header sent by the browser, it is additional security against some attack vectors. Special options: \"all\", \"none\".",
|
||||
|
||||
["API and console options – IPC"]
|
||||
FLAG flag_no_ipc: (bool) = false, or |c: &Config| otry!(c.ipc).disable.clone(),
|
||||
@@ -582,7 +568,7 @@ usage! {
|
||||
|
||||
ARG arg_secretstore_path: (String) = "$BASE/secretstore", or |c: &Config| otry!(c.secretstore).path.clone(),
|
||||
"--secretstore-path=[PATH]",
|
||||
"Specify directory where Secret Store should save its data..",
|
||||
"Specify directory where Secret Store should save its data.",
|
||||
|
||||
ARG arg_secretstore_secret: (Option<String>) = None, or |c: &Config| otry!(c.secretstore).self_secret.clone(),
|
||||
"--secretstore-secret=[SECRET]",
|
||||
@@ -671,7 +657,7 @@ usage! {
|
||||
|
||||
ARG arg_tx_queue_gas: (String) = "off", or |c: &Config| otry!(c.mining).tx_queue_gas.clone(),
|
||||
"--tx-queue-gas=[LIMIT]",
|
||||
"Maximum amount of total gas for external transactions in the queue. LIMIT can be either an amount of gas or 'auto' or 'off'. 'auto' sets the limit to be 20x the current block gas limit..",
|
||||
"Maximum amount of total gas for external transactions in the queue. LIMIT can be either an amount of gas or 'auto' or 'off'. 'auto' sets the limit to be 20x the current block gas limit.",
|
||||
|
||||
ARG arg_tx_queue_strategy: (String) = "gas_price", or |c: &Config| otry!(c.mining).tx_queue_strategy.clone(),
|
||||
"--tx-queue-strategy=[S]",
|
||||
@@ -778,7 +764,7 @@ usage! {
|
||||
|
||||
ARG arg_pruning_history: (u64) = 64u64, or |c: &Config| otry!(c.footprint).pruning_history.clone(),
|
||||
"--pruning-history=[NUM]",
|
||||
"Set a minimum number of recent states to keep when pruning is active..",
|
||||
"Set a minimum number of recent states to keep when pruning is active.",
|
||||
|
||||
ARG arg_pruning_memory: (usize) = 32usize, or |c: &Config| otry!(c.footprint).pruning_memory.clone(),
|
||||
"--pruning-memory=[MB]",
|
||||
@@ -1322,12 +1308,15 @@ mod tests {
|
||||
let args = Args::parse(&["parity", "--secretstore-nodes", "abc@127.0.0.1:3333,cde@10.10.10.10:4444"]).unwrap();
|
||||
assert_eq!(args.arg_secretstore_nodes, "abc@127.0.0.1:3333,cde@10.10.10.10:4444");
|
||||
|
||||
// Arguments with a single value shouldn't accept multiple values
|
||||
let args = Args::parse(&["parity", "--auto-update", "critical", "all"]);
|
||||
assert!(args.is_err());
|
||||
|
||||
let args = Args::parse(&["parity", "--password", "~/.safe/1", "~/.safe/2"]).unwrap();
|
||||
let args = Args::parse(&["parity", "--password", "~/.safe/1", "--password", "~/.safe/2", "--ui-port", "8123", "ui"]).unwrap();
|
||||
assert_eq!(args.arg_password, vec!["~/.safe/1".to_owned(), "~/.safe/2".to_owned()]);
|
||||
assert_eq!(args.arg_ui_port, 8123);
|
||||
assert_eq!(args.cmd_ui, true);
|
||||
|
||||
let args = Args::parse(&["parity", "--password", "~/.safe/1,~/.safe/2", "--ui-port", "8123", "ui"]).unwrap();
|
||||
assert_eq!(args.arg_password, vec!["~/.safe/1".to_owned(), "~/.safe/2".to_owned()]);
|
||||
assert_eq!(args.arg_ui_port, 8123);
|
||||
assert_eq!(args.cmd_ui, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -150,14 +150,20 @@ macro_rules! usage {
|
||||
}
|
||||
) => {
|
||||
use toml;
|
||||
use std::{fs, io, process};
|
||||
use std::{fs, io, process, cmp};
|
||||
use std::io::{Read, Write};
|
||||
use parity_version::version;
|
||||
use clap::{Arg, App, SubCommand, AppSettings, ArgMatches as ClapArgMatches, Error as ClapError, ErrorKind as ClapErrorKind};
|
||||
use clap::{Arg, App, SubCommand, AppSettings, ArgSettings, Error as ClapError, ErrorKind as ClapErrorKind};
|
||||
use dir::helpers::replace_home;
|
||||
use std::ffi::OsStr;
|
||||
use std::collections::HashMap;
|
||||
|
||||
extern crate textwrap;
|
||||
extern crate term_size;
|
||||
use self::textwrap::{Wrapper};
|
||||
|
||||
const MAX_TERM_WIDTH: usize = 120;
|
||||
|
||||
#[cfg(test)]
|
||||
use regex::Regex;
|
||||
|
||||
@@ -365,11 +371,23 @@ macro_rules! usage {
|
||||
#[allow(unused_mut)] // subc_subc_exist may be assigned true by the macro
|
||||
#[allow(unused_assignments)] // Rust issue #22630
|
||||
pub fn print_help() -> String {
|
||||
|
||||
const TAB: &str = " ";
|
||||
const TAB_TAB: &str = " ";
|
||||
|
||||
let term_width = match term_size::dimensions() {
|
||||
None => MAX_TERM_WIDTH,
|
||||
Some((w, _)) => {
|
||||
cmp::min(w, MAX_TERM_WIDTH)
|
||||
}
|
||||
};
|
||||
|
||||
let mut help : String = include_str!("./usage_header.txt").to_owned();
|
||||
|
||||
help.push_str("\n\n");
|
||||
help.push_str("\n");
|
||||
|
||||
// Subcommands
|
||||
let mut subcommands_wrapper = Wrapper::new(term_width).subsequent_indent(TAB);
|
||||
help.push_str("parity [options]\n");
|
||||
$(
|
||||
{
|
||||
@@ -386,11 +404,14 @@ macro_rules! usage {
|
||||
)*
|
||||
];
|
||||
|
||||
if subc_subc_usages.is_empty() {
|
||||
help.push_str(&format!("parity [options] {} {}\n", underscore_to_hyphen!(&stringify!($subc)[4..]), underscore_to_hyphen!(&stringify!($subc_subc)[stringify!($subc).len()+1..])));
|
||||
} else {
|
||||
help.push_str(&format!("parity [options] {} {} {}\n", underscore_to_hyphen!(&stringify!($subc)[4..]), underscore_to_hyphen!(&stringify!($subc_subc)[stringify!($subc).len()+1..]), subc_subc_usages.join(" ")));
|
||||
}
|
||||
help.push_str(&subcommands_wrapper.fill(
|
||||
format!(
|
||||
"parity [options] {} {} {}\n",
|
||||
underscore_to_hyphen!(&stringify!($subc)[4..]),
|
||||
underscore_to_hyphen!(&stringify!($subc_subc)[stringify!($subc).len()+1..]),
|
||||
subc_subc_usages.join(" ")
|
||||
).as_ref())
|
||||
);
|
||||
)*
|
||||
|
||||
// Print the subcommand on its own only if it has no subsubcommands
|
||||
@@ -404,22 +425,30 @@ macro_rules! usage {
|
||||
)*
|
||||
];
|
||||
|
||||
if subc_usages.is_empty() {
|
||||
help.push_str(&format!("parity [options] {}\n", underscore_to_hyphen!(&stringify!($subc)[4..])));
|
||||
} else {
|
||||
help.push_str(&format!("parity [options] {} {}\n", underscore_to_hyphen!(&stringify!($subc)[4..]), subc_usages.join(" ")));
|
||||
}
|
||||
help.push_str(&subcommands_wrapper.fill(
|
||||
format!(
|
||||
"parity [options] {} {}\n",
|
||||
underscore_to_hyphen!(&stringify!($subc)[4..]),
|
||||
subc_usages.join(" ")
|
||||
).as_ref())
|
||||
);
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
||||
help.push_str("\n");
|
||||
|
||||
// Arguments and flags
|
||||
let args_wrapper = Wrapper::new(term_width).initial_indent(TAB_TAB).subsequent_indent(TAB_TAB);
|
||||
$(
|
||||
help.push_str("\n");
|
||||
help.push_str($group_name); help.push_str(":\n");
|
||||
|
||||
$(
|
||||
help.push_str(&format!("\t{}\n\t\t{}\n", $flag_usage, $flag_help));
|
||||
help.push_str(&format!("{}{}\n{}\n",
|
||||
TAB, $flag_usage,
|
||||
args_wrapper.fill($flag_help)
|
||||
));
|
||||
help.push_str("\n");
|
||||
)*
|
||||
|
||||
$(
|
||||
@@ -429,10 +458,24 @@ macro_rules! usage {
|
||||
if_option_vec!(
|
||||
$($arg_type_tt)+,
|
||||
THEN {
|
||||
help.push_str(&format!("\t{}\n\t\t{} (default: {:?})\n", $arg_usage, $arg_help, {let x : inner_option_type!($($arg_type_tt)+)> = $arg_default; x}))
|
||||
help.push_str(&format!("{}{}\n{}\n",
|
||||
TAB, $arg_usage,
|
||||
args_wrapper.fill(format!(
|
||||
"{} (default: {:?})",
|
||||
$arg_help,
|
||||
{let x : inner_option_type!($($arg_type_tt)+)> = $arg_default; x}
|
||||
).as_ref())
|
||||
))
|
||||
}
|
||||
ELSE {
|
||||
help.push_str(&format!("\t{}\n\t\t{}{}\n", $arg_usage, $arg_help, $arg_default.map(|x: inner_option_type!($($arg_type_tt)+)| format!(" (default: {})",x)).unwrap_or("".to_owned())))
|
||||
help.push_str(&format!("{}{}\n{}\n",
|
||||
TAB, $arg_usage,
|
||||
args_wrapper.fill(format!(
|
||||
"{}{}",
|
||||
$arg_help,
|
||||
$arg_default.map(|x: inner_option_type!($($arg_type_tt)+)| format!(" (default: {})",x)).unwrap_or("".to_owned())
|
||||
).as_ref())
|
||||
))
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -440,14 +483,27 @@ macro_rules! usage {
|
||||
if_vec!(
|
||||
$($arg_type_tt)+,
|
||||
THEN {
|
||||
help.push_str(&format!("\t{}\n\t\t{} (default: {:?})\n", $arg_usage, $arg_help, {let x : $($arg_type_tt)+ = $arg_default; x}))
|
||||
help.push_str(&format!("{}{}\n{}\n", TAB, $arg_usage,
|
||||
args_wrapper.fill(format!(
|
||||
"{} (default: {:?})",
|
||||
$arg_help,
|
||||
{let x : $($arg_type_tt)+ = $arg_default; x}
|
||||
).as_ref())
|
||||
))
|
||||
}
|
||||
ELSE {
|
||||
help.push_str(&format!("\t{}\n\t\t{} (default: {})\n", $arg_usage, $arg_help, $arg_default))
|
||||
help.push_str(&format!("{}{}\n{}\n", TAB, $arg_usage,
|
||||
args_wrapper.fill(format!(
|
||||
"{} (default: {})",
|
||||
$arg_help,
|
||||
$arg_default
|
||||
).as_ref())
|
||||
))
|
||||
}
|
||||
)
|
||||
}
|
||||
);
|
||||
help.push_str("\n");
|
||||
)*
|
||||
|
||||
)*
|
||||
@@ -503,36 +559,6 @@ macro_rules! usage {
|
||||
args
|
||||
}
|
||||
|
||||
pub fn hydrate_with_globals(self: &mut Self, matches: &ClapArgMatches) -> Result<(), ClapError> {
|
||||
$(
|
||||
$(
|
||||
self.$flag = self.$flag || matches.is_present(stringify!($flag));
|
||||
)*
|
||||
$(
|
||||
if let some @ Some(_) = return_if_parse_error!(if_option!(
|
||||
$($arg_type_tt)+,
|
||||
THEN {
|
||||
if_option_vec!(
|
||||
$($arg_type_tt)+,
|
||||
THEN { values_t!(matches, stringify!($arg), inner_option_vec_type!($($arg_type_tt)+)) }
|
||||
ELSE { value_t!(matches, stringify!($arg), inner_option_type!($($arg_type_tt)+)) }
|
||||
)
|
||||
}
|
||||
ELSE {
|
||||
if_vec!(
|
||||
$($arg_type_tt)+,
|
||||
THEN { values_t!(matches, stringify!($arg), inner_vec_type!($($arg_type_tt)+)) }
|
||||
ELSE { value_t!(matches, stringify!($arg), $($arg_type_tt)+) }
|
||||
)
|
||||
}
|
||||
)) {
|
||||
self.$arg = some;
|
||||
}
|
||||
)*
|
||||
)*
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(unused_variables)] // the submatches of arg-less subcommands aren't used
|
||||
pub fn parse<S: AsRef<str>>(command: &[S]) -> Result<Self, ClapError> {
|
||||
|
||||
@@ -582,21 +608,31 @@ macro_rules! usage {
|
||||
let matches = App::new("Parity")
|
||||
.global_setting(AppSettings::VersionlessSubcommands)
|
||||
.global_setting(AppSettings::DisableHelpSubcommand)
|
||||
.max_term_width(MAX_TERM_WIDTH)
|
||||
.help(Args::print_help().as_ref())
|
||||
.args(&usages.iter().map(|u| Arg::from_usage(u).use_delimiter(false).allow_hyphen_values(true)).collect::<Vec<Arg>>())
|
||||
.args(&usages.iter().map(|u| {
|
||||
let mut arg = Arg::from_usage(u)
|
||||
.allow_hyphen_values(true) // Allow for example --allow-ips -10.0.0.0/8
|
||||
.global(true) // Argument doesn't have to come before the first subcommand
|
||||
.hidden(true); // Hide global arguments from the (subcommand) help messages generated by Clap
|
||||
|
||||
if arg.is_set(ArgSettings::Multiple) {
|
||||
arg = arg.require_delimiter(true); // Multiple values can only be separated by commas, not spaces (#7428)
|
||||
}
|
||||
|
||||
arg
|
||||
}).collect::<Vec<Arg>>())
|
||||
$(
|
||||
.subcommand(
|
||||
SubCommand::with_name(&underscore_to_hyphen!(&stringify!($subc)[4..]))
|
||||
.about($subc_help)
|
||||
.args(&subc_usages.get(stringify!($subc)).unwrap().iter().map(|u| Arg::from_usage(u).use_delimiter(false).allow_hyphen_values(true)).collect::<Vec<Arg>>())
|
||||
.args(&usages.iter().map(|u| Arg::from_usage(u).use_delimiter(false).allow_hyphen_values(true)).collect::<Vec<Arg>>()) // accept global arguments at this position
|
||||
$(
|
||||
.setting(AppSettings::SubcommandRequired) // prevent from running `parity account`
|
||||
.subcommand(
|
||||
SubCommand::with_name(&underscore_to_hyphen!(&stringify!($subc_subc)[stringify!($subc).len()+1..]))
|
||||
.about($subc_subc_help)
|
||||
.args(&subc_usages.get(stringify!($subc_subc)).unwrap().iter().map(|u| Arg::from_usage(u).use_delimiter(false).allow_hyphen_values(true)).collect::<Vec<Arg>>())
|
||||
.args(&usages.iter().map(|u| Arg::from_usage(u).use_delimiter(false).allow_hyphen_values(true)).collect::<Vec<Arg>>()) // accept global arguments at this position
|
||||
)
|
||||
)*
|
||||
)
|
||||
@@ -605,15 +641,39 @@ macro_rules! usage {
|
||||
|
||||
let mut raw_args : RawArgs = Default::default();
|
||||
|
||||
raw_args.hydrate_with_globals(&matches)?;
|
||||
// Globals
|
||||
$(
|
||||
$(
|
||||
raw_args.$flag = raw_args.$flag || matches.is_present(stringify!($flag));
|
||||
)*
|
||||
$(
|
||||
if let some @ Some(_) = return_if_parse_error!(if_option!(
|
||||
$($arg_type_tt)+,
|
||||
THEN {
|
||||
if_option_vec!(
|
||||
$($arg_type_tt)+,
|
||||
THEN { values_t!(matches, stringify!($arg), inner_option_vec_type!($($arg_type_tt)+)) }
|
||||
ELSE { value_t!(matches, stringify!($arg), inner_option_type!($($arg_type_tt)+)) }
|
||||
)
|
||||
}
|
||||
ELSE {
|
||||
if_vec!(
|
||||
$($arg_type_tt)+,
|
||||
THEN { values_t!(matches, stringify!($arg), inner_vec_type!($($arg_type_tt)+)) }
|
||||
ELSE { value_t!(matches, stringify!($arg), $($arg_type_tt)+) }
|
||||
)
|
||||
}
|
||||
)) {
|
||||
raw_args.$arg = some;
|
||||
}
|
||||
)*
|
||||
)*
|
||||
|
||||
// Subcommands
|
||||
$(
|
||||
if let Some(submatches) = matches.subcommand_matches(&underscore_to_hyphen!(&stringify!($subc)[4..])) {
|
||||
raw_args.$subc = true;
|
||||
|
||||
// Globals
|
||||
raw_args.hydrate_with_globals(&submatches)?;
|
||||
// Subcommand flags
|
||||
$(
|
||||
raw_args.$subc_flag = submatches.is_present(&stringify!($subc_flag));
|
||||
@@ -643,8 +703,6 @@ macro_rules! usage {
|
||||
if let Some(subsubmatches) = submatches.subcommand_matches(&underscore_to_hyphen!(&stringify!($subc_subc)[stringify!($subc).len()+1..])) {
|
||||
raw_args.$subc_subc = true;
|
||||
|
||||
// Globals
|
||||
raw_args.hydrate_with_globals(&subsubmatches)?;
|
||||
// Sub-subcommand flags
|
||||
$(
|
||||
raw_args.$subc_subc_flag = subsubmatches.is_present(&stringify!($subc_subc_flag));
|
||||
|
||||