Merge branch 'master' into ng-contract-dev

This commit is contained in:
Nicolas Gotchac 2016-12-20 02:39:10 +01:00
commit b4c73a52d1
233 changed files with 7673 additions and 2011 deletions

2
.gitignore vendored
View File

@ -32,3 +32,5 @@
out/ out/
.vscode .vscode
/parity.*

View File

@ -20,8 +20,10 @@ linux-stable:
- stable - stable
- triggers - triggers
script: script:
- cargo build -j $(nproc) --release $CARGOFLAGS - curl --data "secret=$RELEASES_SECRET" http://icarus.parity.io:1337/push-release/$CI_BUILD_REF_NAME/$CI_BUILD_REF
- cargo build -j $(nproc) --release --features final $CARGOFLAGS
- strip target/release/parity - strip target/release/parity
- export SHA3=$(target/release/parity tools hash target/release/parity)
- md5sum target/release/parity > parity.md5 - md5sum target/release/parity > parity.md5
- sh scripts/deb-build.sh amd64 - sh scripts/deb-build.sh amd64
- cp target/release/parity deb/usr/bin/parity - cp target/release/parity deb/usr/bin/parity
@ -36,6 +38,7 @@ linux-stable:
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/parity.md5 --body parity.md5 - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/parity.md5 --body parity.md5
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/"parity_"$VER"_amd64.deb" --body "parity_"$VER"_amd64.deb" - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/"parity_"$VER"_amd64.deb" --body "parity_"$VER"_amd64.deb"
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/"parity_"$VER"_amd64.deb.md5" --body "parity_"$VER"_amd64.deb.md5" - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/"parity_"$VER"_amd64.deb.md5" --body "parity_"$VER"_amd64.deb.md5"
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://icarus.parity.io:1337/push-build/$CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu
tags: tags:
- rust - rust
- rust-stable - rust-stable
@ -92,15 +95,18 @@ linux-centos:
script: script:
- export CXX="g++" - export CXX="g++"
- export CC="gcc" - export CC="gcc"
- cargo build -j $(nproc) --release $CARGOFLAGS - export PLATFORM=x86_64-unknown-centos-gnu
- cargo build -j $(nproc) --release --features final $CARGOFLAGS
- strip target/release/parity - strip target/release/parity
- md5sum target/release/parity > parity.md5 - md5sum target/release/parity > parity.md5
- export SHA3=$(target/release/parity tools hash target/release/parity)
- aws configure set aws_access_key_id $s3_key - aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret - aws configure set aws_secret_access_key $s3_secret
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable)$ ]]; then export S3_BUCKET=builds-parity-published; else export S3_BUCKET=builds-parity; fi - if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable)$ ]]; then export S3_BUCKET=builds-parity-published; else export S3_BUCKET=builds-parity; fi
- aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu - aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/parity --body target/release/parity - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/parity --body target/release/parity
- aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/parity.md5 --body parity.md5 - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/parity.md5 --body parity.md5
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://icarus.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
tags: tags:
- rust - rust
- rust-centos - rust-centos
@ -119,22 +125,26 @@ linux-i686:
script: script:
- export HOST_CC=gcc - export HOST_CC=gcc
- export HOST_CXX=g++ - export HOST_CXX=g++
- cargo build -j $(nproc) --target i686-unknown-linux-gnu --release $CARGOFLAGS - export COMMIT=$(git rev-parse HEAD)
- strip target/i686-unknown-linux-gnu/release/parity - export PLATFORM=i686-unknown-linux-gnu
- md5sum target/i686-unknown-linux-gnu/release/parity > parity.md5 - cargo build -j $(nproc) --target i686-unknown-linux-gnu --features final --release $CARGOFLAGS
- 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 - sh scripts/deb-build.sh i386
- cp target/i686-unknown-linux-gnu/release/parity deb/usr/bin/parity - cp target/$PLATFORM/release/parity deb/usr/bin/parity
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n") - export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
- dpkg-deb -b deb "parity_"$VER"_i386.deb" - dpkg-deb -b deb "parity_"$VER"_i386.deb"
- md5sum "parity_"$VER"_i386.deb" > "parity_"$VER"_i386.deb.md5" - md5sum "parity_"$VER"_i386.deb" > "parity_"$VER"_i386.deb.md5"
- aws configure set aws_access_key_id $s3_key - aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret - aws configure set aws_secret_access_key $s3_secret
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable)$ ]]; then export S3_BUCKET=builds-parity-published; else export S3_BUCKET=builds-parity; fi - if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable)$ ]]; 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/i686-unknown-linux-gnu - aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/$PLATFORM
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/i686-unknown-linux-gnu/parity --body target/i686-unknown-linux-gnu/release/parity - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity --body target/$PLATFORM/release/parity
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/i686-unknown-linux-gnu/parity.md5 --body parity.md5 - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity.md5 --body parity.md5
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/i686-unknown-linux-gnu/"parity_"$VER"_i386.deb" --body "parity_"$VER"_i386.deb" - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_i386.deb" --body "parity_"$VER"_i386.deb"
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/i686-unknown-linux-gnu/"parity_"$VER"_i386.deb.md5" --body "parity_"$VER"_i386.deb.md5" - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_i386.deb.md5" --body "parity_"$VER"_i386.deb.md5"
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://icarus.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
tags: tags:
- rust - rust
- rust-i686 - rust-i686
@ -156,27 +166,30 @@ linux-armv7:
- export CXX=arm-linux-gnueabihf-g++ - export CXX=arm-linux-gnueabihf-g++
- export HOST_CC=gcc - export HOST_CC=gcc
- export HOST_CXX=g++ - export HOST_CXX=g++
- export PLATFORM=armv7-unknown-linux-gnueabihf
- rm -rf .cargo - rm -rf .cargo
- mkdir -p .cargo - mkdir -p .cargo
- echo "[target.armv7-unknown-linux-gnueabihf]" >> .cargo/config - echo "[target.$PLATFORM]" >> .cargo/config
- echo "linker= \"arm-linux-gnueabihf-gcc\"" >> .cargo/config - echo "linker= \"arm-linux-gnueabihf-gcc\"" >> .cargo/config
- cat .cargo/config - cat .cargo/config
- cargo build -j $(nproc) --target armv7-unknown-linux-gnueabihf --release $CARGOFLAGS - cargo build -j $(nproc) --target $PLATFORM --features final --release $CARGOFLAGS
- arm-linux-gnueabihf-strip target/armv7-unknown-linux-gnueabihf/release/parity - arm-linux-gnueabihf-strip target/$PLATFORM/release/parity
- md5sum target/armv7-unknown-linux-gnueabihf/release/parity > parity.md5 - export SHA3=$(rhash --sha3-256 ~/Core/parity/target/release/parity -p %h)
- md5sum target/$PLATFORM/release/parity > parity.md5
- sh scripts/deb-build.sh armhf - sh scripts/deb-build.sh armhf
- cp target/armv7-unknown-linux-gnueabihf/release/parity deb/usr/bin/parity - cp target/$PLATFORM/release/parity deb/usr/bin/parity
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n") - export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
- dpkg-deb -b deb "parity_"$VER"_armhf.deb" - dpkg-deb -b deb "parity_"$VER"_armhf.deb"
- md5sum "parity_"$VER"_armhf.deb" > "parity_"$VER"_armhf.deb.md5" - md5sum "parity_"$VER"_armhf.deb" > "parity_"$VER"_armhf.deb.md5"
- aws configure set aws_access_key_id $s3_key - aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret - aws configure set aws_secret_access_key $s3_secret
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable)$ ]]; then export S3_BUCKET=builds-parity-published; else export S3_BUCKET=builds-parity; fi - if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable)$ ]]; 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/armv7-unknown-linux-gnueabihf - aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/$PLATFORM
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/parity --body target/armv7-unknown-linux-gnueabihf/release/parity - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity --body target/$PLATFORM/release/parity
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/parity.md5 --body parity.md5 - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity.md5 --body parity.md5
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/"parity_"$VER"_armhf.deb" --body "parity_"$VER"_armhf.deb" - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_armhf.deb" --body "parity_"$VER"_armhf.deb"
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/"parity_"$VER"_armhf.deb.md5" --body "parity_"$VER"_armhf.deb.md5" - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_armhf.deb.md5" --body "parity_"$VER"_armhf.deb.md5"
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://icarus.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
tags: tags:
- rust - rust
- rust-arm - rust-arm
@ -198,27 +211,30 @@ linux-arm:
- export CXX=arm-linux-gnueabihf-g++ - export CXX=arm-linux-gnueabihf-g++
- export HOST_CC=gcc - export HOST_CC=gcc
- export HOST_CXX=g++ - export HOST_CXX=g++
- export PLATFORM=arm-unknown-linux-gnueabihf
- rm -rf .cargo - rm -rf .cargo
- mkdir -p .cargo - mkdir -p .cargo
- echo "[target.arm-unknown-linux-gnueabihf]" >> .cargo/config - echo "[target.$PLATFORM]" >> .cargo/config
- echo "linker= \"arm-linux-gnueabihf-gcc\"" >> .cargo/config - echo "linker= \"arm-linux-gnueabihf-gcc\"" >> .cargo/config
- cat .cargo/config - cat .cargo/config
- cargo build -j $(nproc) --target arm-unknown-linux-gnueabihf --release $CARGOFLAGS - cargo build -j $(nproc) --target $PLATFORM --features final --release $CARGOFLAGS
- arm-linux-gnueabihf-strip target/arm-unknown-linux-gnueabihf/release/parity - arm-linux-gnueabihf-strip target/$PLATFORM/release/parity
- md5sum target/arm-unknown-linux-gnueabihf/release/parity > parity.md5 - export SHA3=$(rhash --sha3-256 ~/Core/parity/target/release/parity -p %h)
- md5sum target/$PLATFORM/release/parity > parity.md5
- sh scripts/deb-build.sh armhf - sh scripts/deb-build.sh armhf
- cp target/arm-unknown-linux-gnueabihf/release/parity deb/usr/bin/parity - cp target/$PLATFORM/release/parity deb/usr/bin/parity
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n") - export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
- dpkg-deb -b deb "parity_"$VER"_armhf.deb" - dpkg-deb -b deb "parity_"$VER"_armhf.deb"
- md5sum "parity_"$VER"_armhf.deb" > "parity_"$VER"_armhf.deb.md5" - md5sum "parity_"$VER"_armhf.deb" > "parity_"$VER"_armhf.deb.md5"
- aws configure set aws_access_key_id $s3_key - aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret - aws configure set aws_secret_access_key $s3_secret
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable)$ ]]; then export S3_BUCKET=builds-parity-published; else export S3_BUCKET=builds-parity; fi - if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable)$ ]]; 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/arm-unknown-linux-gnueabihf - aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/$PLATFORM
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/parity --body target/arm-unknown-linux-gnueabihf/release/parity - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity --body target/$PLATFORM/release/parity
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/parity.md5 --body parity.md5 - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity.md5 --body parity.md5
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/"parity_"$VER"_armhf.deb" --body "parity_"$VER"_armhf.deb" - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_armhf.deb" --body "parity_"$VER"_armhf.deb"
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/"parity_"$VER"_armhf.deb.md5" --body "parity_"$VER"_armhf.deb.md5" - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_armhf.deb.md5" --body "parity_"$VER"_armhf.deb.md5"
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://icarus.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
tags: tags:
- rust - rust
- rust-arm - rust-arm
@ -240,20 +256,23 @@ linux-armv6:
- export CXX=arm-linux-gnueabi-g++ - export CXX=arm-linux-gnueabi-g++
- export HOST_CC=gcc - export HOST_CC=gcc
- export HOST_CXX=g++ - export HOST_CXX=g++
- export PLATFORM=arm-unknown-linux-gnueabi
- rm -rf .cargo - rm -rf .cargo
- mkdir -p .cargo - mkdir -p .cargo
- echo "[target.arm-unknown-linux-gnueabi]" >> .cargo/config - echo "[target.$PLATFORM]" >> .cargo/config
- echo "linker= \"arm-linux-gnueabi-gcc\"" >> .cargo/config - echo "linker= \"arm-linux-gnueabi-gcc\"" >> .cargo/config
- cat .cargo/config - cat .cargo/config
- cargo build -j $(nproc) --target arm-unknown-linux-gnueabi --release $CARGOFLAGS - cargo build -j $(nproc) --target $PLATFORM --features final --release $CARGOFLAGS
- arm-linux-gnueabi-strip target/arm-unknown-linux-gnueabi/release/parity - arm-linux-gnueabi-strip target/$PLATFORM/release/parity
- md5sum target/arm-unknown-linux-gnueabi/release/parity > parity.md5 - export SHA3=$(rhash --sha3-256 ~/Core/parity/target/release/parity -p %h)
- md5sum target/$PLATFORM/release/parity > parity.md5
- aws configure set aws_access_key_id $s3_key - aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret - aws configure set aws_secret_access_key $s3_secret
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable)$ ]]; then export S3_BUCKET=builds-parity-published; else export S3_BUCKET=builds-parity; fi - if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable)$ ]]; 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/arm-unknown-linux-gnueabi - aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/$PLATFORM
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabi/parity --body target/arm-unknown-linux-gnueabi/release/parity - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity --body target/$PLATFORM/release/parity
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabi/parity.md5 --body parity.md5 - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity.md5 --body parity.md5
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://icarus.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
tags: tags:
- rust - rust
- rust-arm - rust-arm
@ -275,27 +294,29 @@ linux-aarch64:
- export CXX=aarch64-linux-gnu-g++ - export CXX=aarch64-linux-gnu-g++
- export HOST_CC=gcc - export HOST_CC=gcc
- export HOST_CXX=g++ - export HOST_CXX=g++
- export PLATFORM=aarch64-unknown-linux-gnu
- rm -rf .cargo - rm -rf .cargo
- mkdir -p .cargo - mkdir -p .cargo
- echo "[target.aarch64-unknown-linux-gnu]" >> .cargo/config - echo "[target.$PLATFORM]" >> .cargo/config
- echo "linker= \"aarch64-linux-gnu-gcc\"" >> .cargo/config - echo "linker= \"aarch64-linux-gnu-gcc\"" >> .cargo/config
- cat .cargo/config - cat .cargo/config
- cargo build -j $(nproc) --target aarch64-unknown-linux-gnu --release $CARGOFLAGS - cargo build -j $(nproc) --target $PLATFORM --features final --release $CARGOFLAGS
- aarch64-linux-gnu-strip target/aarch64-unknown-linux-gnu/release/parity - aarch64-linux-gnu-strip target/$PLATFORM/release/parity
- md5sum target/aarch64-unknown-linux-gnu/release/parity > parity.md5 - export SHA3=$(rhash --sha3-256 ~/Core/parity/target/release/parity -p %h)
- md5sum target/$PLATFORM/release/parity > parity.md5
- sh scripts/deb-build.sh arm64 - sh scripts/deb-build.sh arm64
- cp target/aarch64-unknown-linux-gnu/release/parity deb/usr/bin/parity - cp target/$PLATFORM/release/parity deb/usr/bin/parity
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n") - export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
- dpkg-deb -b deb "parity_"$VER"_arm64.deb" - dpkg-deb -b deb "parity_"$VER"_arm64.deb"
- md5sum "parity_"$VER"_arm64.deb" > "parity_"$VER"_arm64.deb.md5" - md5sum "parity_"$VER"_arm64.deb" > "parity_"$VER"_arm64.deb.md5"
- aws configure set aws_access_key_id $s3_key - aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret - aws configure set aws_secret_access_key $s3_secret
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable)$ ]]; then export S3_BUCKET=builds-parity-published; else export S3_BUCKET=builds-parity; fi - if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable)$ ]]; 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/aarch64-unknown-linux-gnu - aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/$PLATFORM
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/aarch64-unknown-linux-gnu/parity --body target/aarch64-unknown-linux-gnu/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/aarch64-unknown-linux-gnu/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/aarch64-unknown-linux-gnu/"parity_"$VER"_arm64.deb" --body "parity_"$VER"_arm64.deb" - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity_"$VER"_arm64.deb.md5" --body "parity_"$VER"_arm64.deb.md5"
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/aarch64-unknown-linux-gnu/"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://icarus.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
tags: tags:
- rust - rust
- rust-arm - rust-arm
@ -312,10 +333,13 @@ darwin:
- stable - stable
- triggers - triggers
script: script:
- cargo build -j 8 --release #$CARGOFLAGS - export COMMIT=$(git rev-parse HEAD)
- cargo build -j 8 --release -p ethstore #$CARGOFLAGS - export PLATFORM=x86_64-apple-darwin
- cargo build -j 8 --features final --release #$CARGOFLAGS
- cargo build -j 8 --features final --release -p ethstore #$CARGOFLAGS
- rm -rf parity.md5 - rm -rf parity.md5
- md5sum target/release/parity > parity.md5 - md5sum target/release/parity > parity.md5
- export SHA3=$(target/release/parity tools hash target/release/parity)
- packagesbuild -v mac/Parity.pkgproj - packagesbuild -v mac/Parity.pkgproj
- export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n") - export VER=$(grep -m 1 version Cargo.toml | awk '{print $3}' | tr -d '"' | tr -d "\n")
- mv target/release/Parity\ Ethereum.pkg "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg" - mv target/release/Parity\ Ethereum.pkg "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg"
@ -323,11 +347,12 @@ darwin:
- aws configure set aws_access_key_id $s3_key - aws configure set aws_access_key_id $s3_key
- aws configure set aws_secret_access_key $s3_secret - aws configure set aws_secret_access_key $s3_secret
- if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable)$ ]]; then export S3_BUCKET=builds-parity-published; else export S3_BUCKET=builds-parity; fi - if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable)$ ]]; 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-apple-darwin - aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/$PLATFORM
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-apple-darwin/parity --body target/release/parity - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity --body target/release/parity
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-apple-darwin/parity.md5 --body parity.md5 - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/parity.md5 --body parity.md5
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-apple-darwin/"parity-"$VER"-osx-installer-EXPERIMENTAL.pkg" --body "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg" - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity-"$VER"-osx-installer-EXPERIMENTAL.pkg" --body "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg"
- aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-apple-darwin/"parity-"$VER"-osx-installer-EXPERIMENTAL.pkg.md5" --body "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg.md5" - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/$PLATFORM/"parity-"$VER"-osx-installer-EXPERIMENTAL.pkg.md5" --body "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg.md5"
- curl --data "commit=$CI_BUILD_REF&sha3=$SHA3&filename=parity&secret=$RELEASES_SECRET" http://icarus.parity.io:1337/push-build/$CI_BUILD_REF_NAME/$PLATFORM
tags: tags:
- osx - osx
artifacts: artifacts:
@ -345,15 +370,18 @@ windows:
- stable - stable
- triggers - triggers
script: 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 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 LIB=C:\vs2015\VC\lib;C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10240.0\ucrt\x64
- set RUST_BACKTRACE=1 - set RUST_BACKTRACE=1
- set RUSTFLAGS=%RUSTFLAGS% - set RUSTFLAGS=%RUSTFLAGS%
- rustup default stable-x86_64-pc-windows-msvc - rustup default stable-x86_64-pc-windows-msvc
- cargo build --release #%CARGOFLAGS% - cargo build --features final --release #%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/ethcore/win-build/raw/master/SimpleFC.dll" -o nsis\SimpleFC.dll - curl -sL --url "https://github.com/ethcore/win-build/raw/master/SimpleFC.dll" -o nsis\SimpleFC.dll
- curl -sL --url "https://github.com/ethcore/win-build/raw/master/vc_redist.x64.exe" -o nsis\vc_redist.x64.exe - curl -sL --url "https://github.com/ethcore/win-build/raw/master/vc_redist.x64.exe" -o nsis\vc_redist.x64.exe
- signtool sign /f %keyfile% /p %certpass% target\release\parity.exe
- msbuild windows\ptray\ptray.vcxproj /p:Platform=x64 /p:Configuration=Release - msbuild windows\ptray\ptray.vcxproj /p:Platform=x64 /p:Configuration=Release
- signtool sign /f %keyfile% /p %certpass% windows\ptray\x64\release\ptray.exe - signtool sign /f %keyfile% /p %certpass% windows\ptray\x64\release\ptray.exe
- cd nsis - cd nsis
@ -385,6 +413,7 @@ windows:
- aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/InstallParity.exe.md5 --body nsis\InstallParity.exe.md5 - aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/InstallParity.exe.md5 --body nsis\InstallParity.exe.md5
- aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/win-installer.zip --body nsis\win-installer.zip - aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/win-installer.zip --body nsis\win-installer.zip
- aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/win-installer.zip.md5 --body nsis\win-installer.zip.md5 - aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/win-installer.zip.md5 --body nsis\win-installer.zip.md5
- curl --data "commit=%CI_BUILD_REF%&sha3=%SHA3%&filename=parity.exe&secret=%RELEASES_SECRET%" http://icarus.parity.io:1337/push-build/%CI_BUILD_REF_NAME%/%PLATFORM%
tags: tags:
- rust-windows - rust-windows
artifacts: artifacts:
@ -399,21 +428,22 @@ test-darwin:
- triggers - triggers
before_script: before_script:
- git submodule update --init --recursive - git submodule update --init --recursive
- export RUST_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep -v -e ^js -e ^\\. -e ^LICENSE -e ^README.md -e ^appveyor.yml -e ^test.sh -e ^windows/ -e ^scripts/ -e^mac/ -e ^nsis/ | wc -l)
script: script:
- export RUST_BACKTRACE=1 - export RUST_BACKTRACE=1
- ./test.sh $CARGOFLAGS - if [ $RUST_FILES_MODIFIED -eq 0 ]; then echo "Skipping Rust tests since no Rust files modified."; else ./test.sh $CARGOFLAGS; fi
tags: tags:
- osx - osx
allow_failure: true allow_failure: true
test-windows: test-windows:
stage: test stage: test
only: only:
# - triggers - triggers
before_script: before_script:
- git submodule update --init --recursive - git submodule update --init --recursive
script: script:
- set RUST_BACKTRACE=1 - set RUST_BACKTRACE=1
- cargo -j 8 test --features json-tests -p rlp -p ethash -p ethcore -p ethcore-bigint -p ethcore-dapps -p ethcore-rpc -p ethcore-signer -p ethcore-util -p ethcore-network -p ethcore-io -p ethkey -p ethstore -p ethsync -p ethcore-ipc -p ethcore-ipc-tests -p ethcore-ipc-nano -p parity %CARGOFLAGS% --verbose --release - echo cargo test --features json-tests -p rlp -p ethash -p ethcore -p ethcore-bigint -p ethcore-dapps -p ethcore-rpc -p ethcore-signer -p ethcore-util -p ethcore-network -p ethcore-io -p ethkey -p ethstore -p ethsync -p ethcore-ipc -p ethcore-ipc-tests -p ethcore-ipc-nano -p parity %CARGOFLAGS% --verbose --release
tags: tags:
- rust-windows - rust-windows
allow_failure: true allow_failure: true
@ -448,10 +478,10 @@ test-rust-beta:
image: ethcore/rust:beta image: ethcore/rust:beta
before_script: before_script:
- git submodule update --init --recursive - git submodule update --init --recursive
- export RUST_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep -v -e ^js -e ^\\. -e ^LICENSE -e ^README.md -e ^appveyor.yml -e ^test.sh -e ^windows/ -e ^scripts/ -e^mac/ -e ^nsis/ | wc -l)
script: script:
- export RUST_BACKTRACE=1 - export RUST_BACKTRACE=1
- echo $JS_FILES_MODIFIED - if [ $RUST_FILES_MODIFIED -eq 0 ]; then echo "Skipping Rust tests since no Rust files modified."; else ./test.sh $CARGOFLAGS; fi
- ./test.sh $CARGOFLAGS
tags: tags:
- rust - rust
- rust-beta - rust-beta
@ -463,9 +493,10 @@ test-rust-nightly:
image: ethcore/rust:nightly image: ethcore/rust:nightly
before_script: before_script:
- git submodule update --init --recursive - git submodule update --init --recursive
- export RUST_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep -v -e ^js -e ^\\. -e ^LICENSE -e ^README.md -e ^appveyor.yml -e ^test.sh -e ^windows/ -e ^scripts/ -e^mac/ -e ^nsis/ | wc -l)
script: script:
- export RUST_BACKTRACE=1 - export RUST_BACKTRACE=1
- ./test.sh $CARGOFLAGS - if [ $RUST_FILES_MODIFIED -eq 0 ]; then echo "Skipping Rust tests since no Rust files modified."; else ./test.sh $CARGOFLAGS; fi
tags: tags:
- rust - rust
- rust-nightly - rust-nightly

256
Cargo.lock generated
View File

@ -3,6 +3,7 @@ name = "parity"
version = "1.5.0" version = "1.5.0"
dependencies = [ dependencies = [
"ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
"ctrlc 1.1.1 (git+https://github.com/ethcore/rust-ctrlc.git)", "ctrlc 1.1.1 (git+https://github.com/ethcore/rust-ctrlc.git)",
"daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -11,7 +12,6 @@ dependencies = [
"ethcore 1.5.0", "ethcore 1.5.0",
"ethcore-dapps 1.5.0", "ethcore-dapps 1.5.0",
"ethcore-devtools 1.5.0", "ethcore-devtools 1.5.0",
"ethcore-hash-fetch 1.5.0",
"ethcore-io 1.5.0", "ethcore-io 1.5.0",
"ethcore-ipc 1.5.0", "ethcore-ipc 1.5.0",
"ethcore-ipc-codegen 1.5.0", "ethcore-ipc-codegen 1.5.0",
@ -32,17 +32,21 @@ dependencies = [
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-hash-fetch 1.5.0",
"parity-rpc-client 1.4.0",
"parity-updater 1.5.0",
"regex 0.1.68 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.1.68 (registry+https://github.com/rust-lang/crates.io-index)",
"rlp 0.1.0", "rlp 0.1.0",
"rpassword 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rpassword 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rpc-cli 1.4.0",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -58,6 +62,17 @@ name = "ansi_term"
version = "0.7.2" version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "app_dirs"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"xdg 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "arrayvec" name = "arrayvec"
version = "0.3.16" version = "0.3.16"
@ -196,7 +211,7 @@ source = "git+https://github.com/ethcore/rust-ctrlc.git#f4927770f89eca80ec250911
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -277,7 +292,7 @@ name = "ethash"
version = "1.5.0" version = "1.5.0"
dependencies = [ dependencies = [
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"primal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "primal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"sha3 0.1.0", "sha3 0.1.0",
] ]
@ -292,6 +307,7 @@ dependencies = [
"clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ethash 1.5.0", "ethash 1.5.0",
"ethcore-bloom-journal 0.1.0", "ethcore-bloom-journal 0.1.0",
"ethcore-devtools 1.5.0", "ethcore-devtools 1.5.0",
@ -316,7 +332,7 @@ dependencies = [
"rlp 0.1.0", "rlp 0.1.0",
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"transient-hashmap 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "transient-hashmap 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -345,7 +361,6 @@ dependencies = [
"clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-devtools 1.5.0", "ethcore-devtools 1.5.0",
"ethcore-hash-fetch 1.5.0",
"ethcore-rpc 1.5.0", "ethcore-rpc 1.5.0",
"ethcore-util 1.5.0", "ethcore-util 1.5.0",
"fetch 0.1.0", "fetch 0.1.0",
@ -357,6 +372,7 @@ dependencies = [
"mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-hash-fetch 1.5.0",
"parity-ui 1.5.0", "parity-ui 1.5.0",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
@ -376,18 +392,6 @@ dependencies = [
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "ethcore-hash-fetch"
version = "1.5.0"
dependencies = [
"ethabi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-util 1.5.0",
"fetch 0.1.0",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "ethcore-io" name = "ethcore-io"
version = "1.5.0" version = "1.5.0"
@ -395,7 +399,7 @@ dependencies = [
"crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.1 (git+https://github.com/ethcore/mio)", "mio 0.6.1 (git+https://github.com/ethcore/mio)",
"parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -406,7 +410,7 @@ dependencies = [
"ethcore-devtools 1.5.0", "ethcore-devtools 1.5.0",
"ethcore-util 1.5.0", "ethcore-util 1.5.0",
"nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)", "nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)",
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -429,7 +433,7 @@ dependencies = [
"ethcore-ipc-nano 1.5.0", "ethcore-ipc-nano 1.5.0",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)", "nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)",
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -454,7 +458,7 @@ dependencies = [
"ethcore-util 1.5.0", "ethcore-util 1.5.0",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)", "nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)",
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -500,7 +504,7 @@ dependencies = [
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.1 (git+https://github.com/ethcore/mio)", "mio 0.6.1 (git+https://github.com/ethcore/mio)",
"parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rlp 0.1.0", "rlp 0.1.0",
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
@ -532,8 +536,10 @@ dependencies = [
"jsonrpc-ipc-server 0.2.4 (git+https://github.com/ethcore/jsonrpc.git)", "jsonrpc-ipc-server 0.2.4 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-macros 0.1.0 (git+https://github.com/ethcore/jsonrpc.git)", "jsonrpc-macros 0.1.0 (git+https://github.com/ethcore/jsonrpc.git)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-updater 1.5.0",
"rlp 0.1.0", "rlp 0.1.0",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_codegen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde_codegen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -575,7 +581,7 @@ dependencies = [
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)", "mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)",
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -597,7 +603,7 @@ dependencies = [
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"lru-cache 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.68 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.1.68 (registry+https://github.com/rust-lang/crates.io-index)",
"rlp 0.1.0", "rlp 0.1.0",
@ -659,7 +665,7 @@ dependencies = [
"itertools 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
@ -688,10 +694,10 @@ dependencies = [
"ethkey 0.2.0", "ethkey 0.2.0",
"heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rlp 0.1.0", "rlp 0.1.0",
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -729,6 +735,14 @@ dependencies = [
"miniz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "miniz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "futures"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "gcc" name = "gcc"
version = "0.3.35" version = "0.3.35"
@ -772,6 +786,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "https-fetch" name = "https-fetch"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ethabi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)", "mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)",
"rustls 0.1.2 (git+https://github.com/ctz/rustls)", "rustls 0.1.2 (git+https://github.com/ctz/rustls)",
@ -838,6 +853,17 @@ dependencies = [
"xmltree 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "xmltree 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "ipc-common-types"
version = "1.5.0"
dependencies = [
"ethcore-ipc 1.5.0",
"ethcore-ipc-codegen 1.5.0",
"ethcore-util 1.5.0",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "isatty" name = "isatty"
version = "0.1.1" version = "0.1.1"
@ -845,7 +871,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -864,7 +890,7 @@ version = "4.0.0"
source = "git+https://github.com/ethcore/jsonrpc.git#33262d626a294a00c20435dec331058ba65e224a" source = "git+https://github.com/ethcore/jsonrpc.git#33262d626a294a00c20435dec331058ba65e224a"
dependencies = [ dependencies = [
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_codegen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde_codegen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -925,7 +951,7 @@ name = "kernel32-sys"
version = "0.2.2" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1026,7 +1052,7 @@ dependencies = [
"nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1042,7 +1068,7 @@ dependencies = [
"nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1057,7 +1083,7 @@ dependencies = [
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.2.0 (git+https://github.com/carllerche/slab?rev=5476efcafb)", "slab 0.2.0 (git+https://github.com/carllerche/slab?rev=5476efcafb)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1073,7 +1099,7 @@ dependencies = [
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1083,7 +1109,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1094,7 +1120,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1123,7 +1149,7 @@ dependencies = [
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1262,6 +1288,15 @@ name = "odds"
version = "0.2.12" version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ole32-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "owning_ref" name = "owning_ref"
version = "0.2.2" version = "0.2.2"
@ -1281,6 +1316,38 @@ dependencies = [
"syntex_syntax 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_syntax 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "parity-hash-fetch"
version = "1.5.0"
dependencies = [
"ethabi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-util 1.5.0",
"fetch 0.1.0",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parity-rpc-client"
version = "1.4.0"
dependencies = [
"ethcore-rpc 1.5.0",
"ethcore-signer 1.5.0",
"ethcore-util 1.5.0",
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ws 0.5.3 (git+https://github.com/ethcore/ws-rs.git?branch=mio-upstream-stable)",
]
[[package]] [[package]]
name = "parity-ui" name = "parity-ui"
version = "1.5.0" version = "1.5.0"
@ -1300,14 +1367,30 @@ dependencies = [
[[package]] [[package]]
name = "parity-ui-precompiled" name = "parity-ui-precompiled"
version = "1.4.0" version = "1.4.0"
source = "git+https://github.com/ethcore/js-precompiled.git#175003ae159b126302fd1a90dd875dc86d7adba0" source = "git+https://github.com/ethcore/js-precompiled.git#e3e33f97c0f3b3d788a859b5bd10f5ca1ee45871"
dependencies = [ dependencies = [
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "parity-updater"
version = "1.5.0"
dependencies = [
"ethabi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore 1.5.0",
"ethcore-ipc 1.5.0",
"ethcore-ipc-codegen 1.5.0",
"ethcore-util 1.5.0",
"ethsync 1.5.0",
"ipc-common-types 1.5.0",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-hash-fetch 1.5.0",
"target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.3.5" version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1323,7 +1406,7 @@ dependencies = [
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1546,7 +1629,30 @@ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rpassword"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rpc-cli"
version = "1.4.0"
dependencies = [
"ethcore-bigint 0.1.2",
"ethcore-rpc 1.5.0",
"ethcore-util 1.5.0",
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-rpc-client 1.4.0",
"rpassword 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1600,6 +1706,23 @@ dependencies = [
"nom 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "nom 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "semver"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver-parser 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver-parser"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.68 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "serde" name = "serde"
version = "0.8.4" version = "0.8.4"
@ -1650,6 +1773,15 @@ dependencies = [
"gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "shell32-sys"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "siphasher" name = "siphasher"
version = "0.1.1" version = "0.1.1"
@ -1779,13 +1911,21 @@ name = "target_info"
version = "0.1.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "tempdir"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "term" name = "term"
version = "0.2.14" version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1794,7 +1934,7 @@ version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1829,7 +1969,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1925,7 +2065,7 @@ name = "vecio"
version = "0.1.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1956,7 +2096,7 @@ dependencies = [
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.2.6" version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@ -1984,10 +2124,15 @@ name = "ws2_32-sys"
version = "0.2.1" version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "xdg"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "xml-rs" name = "xml-rs"
version = "0.3.4" version = "0.3.4"
@ -2018,6 +2163,7 @@ dependencies = [
[metadata] [metadata]
"checksum aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67077478f0a03952bed2e6786338d400d40c25e9836e08ad50af96607317fd03" "checksum aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67077478f0a03952bed2e6786338d400d40c25e9836e08ad50af96607317fd03"
"checksum ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1f46cd5b1d660c938e3f92dfe7a73d832b3281479363dd0cd9c1c2fbf60f7962" "checksum ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1f46cd5b1d660c938e3f92dfe7a73d832b3281479363dd0cd9c1c2fbf60f7962"
"checksum app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7d1c0d48a81bbb13043847f957971f4d87c81542d80ece5e84ba3cba4058fd4"
"checksum arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "16e3bdb2f54b3ace0285975d59a97cf8ed3855294b2b6bc651fcf22a9c352975" "checksum arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "16e3bdb2f54b3ace0285975d59a97cf8ed3855294b2b6bc651fcf22a9c352975"
"checksum aster 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07d344974f0a155f091948aa389fb1b912d3a58414fbdb9c8d446d193ee3496a" "checksum aster 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07d344974f0a155f091948aa389fb1b912d3a58414fbdb9c8d446d193ee3496a"
"checksum aster 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4df293303e8a52e1df7984ac1415e195f5fcbf51e4bb7bda54557861a3954a08" "checksum aster 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4df293303e8a52e1df7984ac1415e195f5fcbf51e4bb7bda54557861a3954a08"
@ -2048,6 +2194,7 @@ dependencies = [
"checksum ethabi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0c53453517f620847be51943db329276ae52f2e210cfc659e81182864be2f" "checksum ethabi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0c53453517f620847be51943db329276ae52f2e210cfc659e81182864be2f"
"checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" "checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa"
"checksum flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "3eeb481e957304178d2e782f2da1257f1434dfecbae883bafb61ada2a9fea3bb" "checksum flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "3eeb481e957304178d2e782f2da1257f1434dfecbae883bafb61ada2a9fea3bb"
"checksum futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bad0a2ac64b227fdc10c254051ae5af542cf19c9328704fd4092f7914196897"
"checksum gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "91ecd03771effb0c968fd6950b37e89476a578aaf1c70297d8e92b6516ec3312" "checksum gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "91ecd03771effb0c968fd6950b37e89476a578aaf1c70297d8e92b6516ec3312"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
"checksum hamming 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65043da274378d68241eb9a8f8f8aa54e349136f7b8e12f63e3ef44043cc30e1" "checksum hamming 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65043da274378d68241eb9a8f8f8aa54e349136f7b8e12f63e3ef44043cc30e1"
@ -2104,10 +2251,11 @@ dependencies = [
"checksum num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "51fedae97a05f7353612fe017ab705a37e6db8f4d67c5c6fe739a9e70d6eed09" "checksum num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "51fedae97a05f7353612fe017ab705a37e6db8f4d67c5c6fe739a9e70d6eed09"
"checksum number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "084d05f4bf60621a9ac9bde941a410df548f4de9545f06e5ee9d3aef4b97cd77" "checksum number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "084d05f4bf60621a9ac9bde941a410df548f4de9545f06e5ee9d3aef4b97cd77"
"checksum odds 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "b28c06e81b0f789122d415d6394b5fe849bde8067469f4c2980d3cdc10c78ec1" "checksum odds 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "b28c06e81b0f789122d415d6394b5fe849bde8067469f4c2980d3cdc10c78ec1"
"checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c"
"checksum owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8d91377085359426407a287ab16884a0111ba473aa6844ff01d4ec20ce3d75e7" "checksum owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8d91377085359426407a287ab16884a0111ba473aa6844ff01d4ec20ce3d75e7"
"checksum parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98378dec0a185da2b7180308752f0bad73aaa949c3e0a3b0528d0e067945f7ab" "checksum parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98378dec0a185da2b7180308752f0bad73aaa949c3e0a3b0528d0e067945f7ab"
"checksum parity-ui-precompiled 1.4.0 (git+https://github.com/ethcore/js-precompiled.git)" = "<none>" "checksum parity-ui-precompiled 1.4.0 (git+https://github.com/ethcore/js-precompiled.git)" = "<none>"
"checksum parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "dbc5847584161f273e69edc63c1a86254a22f570a0b5dd87aa6f9773f6f7d125" "checksum parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e1435e7a2a00dfebededd6c6bdbd54008001e94b4a2aadd6aef0dc4c56317621"
"checksum parking_lot_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb1b97670a2ffadce7c397fb80a3d687c4f3060140b885621ef1653d0e5d5068" "checksum parking_lot_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb1b97670a2ffadce7c397fb80a3d687c4f3060140b885621ef1653d0e5d5068"
"checksum phf 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "447d9d45f2e0b4a9b532e808365abf18fc211be6ca217202fcd45236ef12f026" "checksum phf 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "447d9d45f2e0b4a9b532e808365abf18fc211be6ca217202fcd45236ef12f026"
"checksum phf_codegen 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "8af7ae7c3f75a502292b491e5cc0a1f69e3407744abe6e57e2a3b712bb82f01d" "checksum phf_codegen 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "8af7ae7c3f75a502292b491e5cc0a1f69e3407744abe6e57e2a3b712bb82f01d"
@ -2134,17 +2282,21 @@ dependencies = [
"checksum rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)" = "<none>" "checksum rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)" = "<none>"
"checksum rotor 0.6.3 (git+https://github.com/ethcore/rotor)" = "<none>" "checksum rotor 0.6.3 (git+https://github.com/ethcore/rotor)" = "<none>"
"checksum rpassword 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5d3a99497c5c544e629cc8b359ae5ede321eba5fa8e5a8078f3ced727a976c3f" "checksum rpassword 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5d3a99497c5c544e629cc8b359ae5ede321eba5fa8e5a8078f3ced727a976c3f"
"checksum rpassword 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab6e42be826e215f30ff830904f8f4a0933c6e2ae890e1af8b408f5bae60081e"
"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" "checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b" "checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" "checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
"checksum rustls 0.1.2 (git+https://github.com/ctz/rustls)" = "<none>" "checksum rustls 0.1.2 (git+https://github.com/ctz/rustls)" = "<none>"
"checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" "checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac"
"checksum semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2d5b7638a1f03815d94e88cb3b3c08e87f0db4d683ef499d1836aaf70a45623f" "checksum semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2d5b7638a1f03815d94e88cb3b3c08e87f0db4d683ef499d1836aaf70a45623f"
"checksum semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae2ff60ecdb19c255841c066cbfa5f8c2a4ada1eb3ae47c77ab6667128da71f5"
"checksum semver-parser 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e88e43a5a74dd2a11707f9c21dfd4a423c66bd871df813227bb0a3e78f3a1ae9"
"checksum serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b1dfda9ebb31d29fa8b94d7eb3031a86a8dcec065f0fe268a30f98867bf45775" "checksum serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b1dfda9ebb31d29fa8b94d7eb3031a86a8dcec065f0fe268a30f98867bf45775"
"checksum serde_codegen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e422ae53d7933f59c6ff57e7b5870b5c9094b1f473f78ec33d89f8a692c3ec02" "checksum serde_codegen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e422ae53d7933f59c6ff57e7b5870b5c9094b1f473f78ec33d89f8a692c3ec02"
"checksum serde_codegen_internals 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f877e2781ed0a323295d1c9f0e26556117b5a11489fc47b1848dfb98b3173d21" "checksum serde_codegen_internals 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f877e2781ed0a323295d1c9f0e26556117b5a11489fc47b1848dfb98b3173d21"
"checksum serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e10f8a9d94b06cf5d3bef66475f04c8ff90950f1be7004c357ff9472ccbaebc" "checksum serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e10f8a9d94b06cf5d3bef66475f04c8ff90950f1be7004c357ff9472ccbaebc"
"checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c" "checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c"
"checksum shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72f20b8f3c060374edb8046591ba28f62448c369ccbdc7b02075103fb3a9e38d"
"checksum siphasher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c44e42fa187b5a8782489cf7740cc27c3125806be2bf33563cf5e02e9533fcd" "checksum siphasher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c44e42fa187b5a8782489cf7740cc27c3125806be2bf33563cf5e02e9533fcd"
"checksum slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d807fd58c4181bbabed77cb3b891ba9748241a552bcc5be698faaebefc54f46e" "checksum slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d807fd58c4181bbabed77cb3b891ba9748241a552bcc5be698faaebefc54f46e"
"checksum slab 0.2.0 (git+https://github.com/carllerche/slab?rev=5476efcafb)" = "<none>" "checksum slab 0.2.0 (git+https://github.com/carllerche/slab?rev=5476efcafb)" = "<none>"
@ -2162,6 +2314,7 @@ dependencies = [
"checksum syntex_syntax 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44bded3cabafc65c90b663b1071bd2d198a9ab7515e6ce729e4570aaf53c407e" "checksum syntex_syntax 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44bded3cabafc65c90b663b1071bd2d198a9ab7515e6ce729e4570aaf53c407e"
"checksum syntex_syntax 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7628a0506e8f9666fdabb5f265d0059b059edac9a3f810bda077abb5d826bd8d" "checksum syntex_syntax 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7628a0506e8f9666fdabb5f265d0059b059edac9a3f810bda077abb5d826bd8d"
"checksum target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c63f48baada5c52e65a29eef93ab4f8982681b67f9e8d29c7b05abcfec2b9ffe" "checksum target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c63f48baada5c52e65a29eef93ab4f8982681b67f9e8d29c7b05abcfec2b9ffe"
"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
"checksum term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "f2077e54d38055cf1ca0fd7933a2e00cd3ec8f6fed352b2a377f06dcdaaf3281" "checksum term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "f2077e54d38055cf1ca0fd7933a2e00cd3ec8f6fed352b2a377f06dcdaaf3281"
"checksum term 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3deff8a2b3b6607d6d7cc32ac25c0b33709453ca9cceac006caac51e963cf94a" "checksum term 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3deff8a2b3b6607d6d7cc32ac25c0b33709453ca9cceac006caac51e963cf94a"
"checksum termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d9cf598a6d7ce700a4e6a9199da127e6819a61e64b68609683cc9a01b5683a" "checksum termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d9cf598a6d7ce700a4e6a9199da127e6819a61e64b68609683cc9a01b5683a"
@ -2185,10 +2338,11 @@ dependencies = [
"checksum vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56b639f935488eb40f06d17c3e3bcc3054f6f75d264e187b1107c8d1cba8d31c" "checksum vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56b639f935488eb40f06d17c3e3bcc3054f6f75d264e187b1107c8d1cba8d31c"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum webpki 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "813503a5985585e0812d430cd1328ee322f47f66629c8ed4ecab939cf9e92f91" "checksum webpki 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "813503a5985585e0812d430cd1328ee322f47f66629c8ed4ecab939cf9e92f91"
"checksum winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4dfaaa8fbdaa618fa6914b59b2769d690dd7521920a18d84b42d254678dd5fd4" "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 winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
"checksum ws 0.5.3 (git+https://github.com/ethcore/ws-rs.git?branch=mio-upstream-stable)" = "<none>" "checksum ws 0.5.3 (git+https://github.com/ethcore/ws-rs.git?branch=mio-upstream-stable)" = "<none>"
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
"checksum xdg 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77b831a5ba77110f438f0ac5583aafeb087f70432998ba6b7dcb1d32185db453"
"checksum xml-rs 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "65e74b96bd3179209dc70a980da6df843dff09e46eee103a0376c0949257e3ef" "checksum xml-rs 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "65e74b96bd3179209dc70a980da6df843dff09e46eee103a0376c0949257e3ef"
"checksum xmltree 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "472a9d37c7c53ab2391161df5b89b1f3bf76dab6ab150d7941ecbdd832282082" "checksum xmltree 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "472a9d37c7c53ab2391161df5b89b1f3bf76dab6ab150d7941ecbdd832282082"
"checksum zip 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "3ceb33a75b3d0608942302eed325b59d2c3ed777cc6c01627ae14e5697c6a31c" "checksum zip 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "3ceb33a75b3d0608942302eed325b59d2c3ed777cc6c01627ae14e5697c6a31c"

View File

@ -1,5 +1,5 @@
[package] [package]
description = "Ethcore client." description = "Parity Ethereum client"
name = "parity" name = "parity"
version = "1.5.0" version = "1.5.0"
license = "GPL-3.0" license = "GPL-3.0"
@ -20,7 +20,7 @@ time = "0.1"
num_cpus = "0.2" num_cpus = "0.2"
number_prefix = "0.2" number_prefix = "0.2"
rpassword = "0.2.1" rpassword = "0.2.1"
semver = "0.2" semver = "0.5"
ansi_term = "0.7" ansi_term = "0.7"
lazy_static = "0.2" lazy_static = "0.2"
regex = "0.1" regex = "0.1"
@ -28,26 +28,30 @@ isatty = "0.1"
toml = "0.2" toml = "0.2"
serde = "0.8.0" serde = "0.8.0"
serde_json = "0.8.0" serde_json = "0.8.0"
app_dirs = "1.1.1"
hyper = { version = "0.9", default-features = false } hyper = { version = "0.9", default-features = false }
ctrlc = { git = "https://github.com/ethcore/rust-ctrlc.git" } ctrlc = { git = "https://github.com/ethcore/rust-ctrlc.git" }
fdlimit = "0.1" fdlimit = "0.1"
clippy = { version = "0.0.103", optional = true}
rlp = { path = "util/rlp" }
ethsync = { path = "sync" }
ethcore = { path = "ethcore" } ethcore = { path = "ethcore" }
ethcore-util = { path = "util" } ethcore-util = { path = "util" }
ethsync = { path = "sync" }
ethcore-io = { path = "util/io" } ethcore-io = { path = "util/io" }
ethcore-devtools = { path = "devtools" } ethcore-devtools = { path = "devtools" }
ethcore-rpc = { path = "rpc" } ethcore-rpc = { path = "rpc" }
ethcore-signer = { path = "signer" } ethcore-signer = { path = "signer" }
ethcore-ipc-nano = { path = "ipc/nano" }
ethcore-ipc = { path = "ipc/rpc" } ethcore-ipc = { path = "ipc/rpc" }
ethcore-ipc-nano = { path = "ipc/nano" }
ethcore-ipc-hypervisor = { path = "ipc/hypervisor" } ethcore-ipc-hypervisor = { path = "ipc/hypervisor" }
ethcore-logger = { path = "logger" } ethcore-logger = { path = "logger" }
ethcore-hash-fetch = { path = "ethcore/hash-fetch" }
rlp = { path = "util/rlp" }
ethcore-stratum = { path = "stratum" } ethcore-stratum = { path = "stratum" }
ethcore-dapps = { path = "dapps", optional = true } ethcore-dapps = { path = "dapps", optional = true }
clippy = { version = "0.0.103", optional = true} rpc-cli = { path = "rpc_cli" }
parity-rpc-client = { path = "rpc_client" }
ethcore-light = { path = "ethcore/light" } ethcore-light = { path = "ethcore/light" }
parity-hash-fetch = { path = "hash-fetch" }
parity-updater = { path = "updater" }
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
winapi = "0.2" winapi = "0.2"
@ -57,7 +61,6 @@ daemonize = "0.2"
[features] [features]
default = ["ui-precompiled"] default = ["ui-precompiled"]
ui = [ ui = [
"dapps", "dapps",
"ethcore-dapps/ui", "ethcore-dapps/ui",
@ -68,7 +71,6 @@ ui-precompiled = [
"ethcore-signer/ui-precompiled", "ethcore-signer/ui-precompiled",
"ethcore-dapps/ui-precompiled", "ethcore-dapps/ui-precompiled",
] ]
dapps = ["ethcore-dapps"] dapps = ["ethcore-dapps"]
ipc = ["ethcore/ipc", "ethsync/ipc"] ipc = ["ethcore/ipc", "ethsync/ipc"]
jit = ["ethcore/jit"] jit = ["ethcore/jit"]
@ -81,6 +83,7 @@ ethstore-cli = ["ethcore/ethstore-cli"]
evm-debug = ["ethcore/evm-debug"] evm-debug = ["ethcore/evm-debug"]
evm-debug-tests = ["ethcore/evm-debug-tests"] evm-debug-tests = ["ethcore/evm-debug-tests"]
slow-blocks = ["ethcore/slow-blocks"] slow-blocks = ["ethcore/slow-blocks"]
final = ["ethcore-util/final"]
[[bin]] [[bin]]
path = "parity/main.rs" path = "parity/main.rs"

View File

@ -6,7 +6,7 @@ environment:
certpass: certpass:
secure: 0BgXJqxq9Ei34/hZ7121FQ== secure: 0BgXJqxq9Ei34/hZ7121FQ==
keyfile: C:\users\appveyor\Certificates.p12 keyfile: C:\users\appveyor\Certificates.p12
RUSTFLAGS: -Zorbit=off -D warnings RUSTFLAGS: -D warnings
branches: branches:
only: only:
@ -19,10 +19,10 @@ branches:
install: install:
- git submodule update --init --recursive - git submodule update --init --recursive
- ps: Install-Product node 6 - ps: Install-Product node 6
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.12.0-x86_64-pc-windows-msvc.exe" - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.13.0-x86_64-pc-windows-msvc.exe"
- ps: Start-FileDownload "https://github.com/ethcore/win-build/raw/master/SimpleFC.dll" -FileName nsis\SimpleFC.dll - ps: Start-FileDownload "https://github.com/ethcore/win-build/raw/master/SimpleFC.dll" -FileName nsis\SimpleFC.dll
- ps: Start-FileDownload "https://github.com/ethcore/win-build/raw/master/vc_redist.x64.exe" -FileName nsis\vc_redist.x64.exe - ps: Start-FileDownload "https://github.com/ethcore/win-build/raw/master/vc_redist.x64.exe" -FileName nsis\vc_redist.x64.exe
- rust-1.12.0-x86_64-pc-windows-msvc.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" - rust-1.13.0-x86_64-pc-windows-msvc.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
- SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin;C:\Program Files (x86)\NSIS;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Bin - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin;C:\Program Files (x86)\NSIS;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Bin
- rustc -V - rustc -V
- cargo -V - cargo -V

View File

@ -30,9 +30,9 @@ zip = { version = "0.1", default-features = false }
ethcore-devtools = { path = "../devtools" } ethcore-devtools = { path = "../devtools" }
ethcore-rpc = { path = "../rpc" } ethcore-rpc = { path = "../rpc" }
ethcore-util = { path = "../util" } ethcore-util = { path = "../util" }
ethcore-hash-fetch = { path = "../ethcore/hash-fetch" }
fetch = { path = "../util/fetch" } fetch = { path = "../util/fetch" }
parity-ui = { path = "./ui" } parity-ui = { path = "./ui" }
parity-hash-fetch = { path = "../hash-fetch" }
clippy = { version = "0.0.103", optional = true} clippy = { version = "0.0.103", optional = true}

View File

@ -120,7 +120,7 @@ impl<R: URLHint> ContentFetcher<R> {
// Content is already being fetched // Content is already being fetched
Some(&mut ContentStatus::Fetching(ref fetch_control)) => { Some(&mut ContentStatus::Fetching(ref fetch_control)) => {
trace!(target: "dapps", "Content fetching in progress. Waiting..."); trace!(target: "dapps", "Content fetching in progress. Waiting...");
(None, fetch_control.to_handler(control)) (None, fetch_control.to_async_handler(path, control))
}, },
// We need to start fetching the content // We need to start fetching the content
None => { None => {
@ -129,11 +129,12 @@ impl<R: URLHint> ContentFetcher<R> {
let content = self.resolver.resolve(content_hex); let content = self.resolver.resolve(content_hex);
let cache = self.cache.clone(); let cache = self.cache.clone();
let on_done = move |id: String, result: Option<LocalPageEndpoint>| { let id = content_id.clone();
let on_done = move |result: Option<LocalPageEndpoint>| {
let mut cache = cache.lock(); let mut cache = cache.lock();
match result { match result {
Some(endpoint) => { Some(endpoint) => {
cache.insert(id, ContentStatus::Ready(endpoint)); cache.insert(id.clone(), ContentStatus::Ready(endpoint));
}, },
// In case of error // In case of error
None => { None => {
@ -150,6 +151,7 @@ impl<R: URLHint> ContentFetcher<R> {
Some(URLHintResult::Dapp(dapp)) => { Some(URLHintResult::Dapp(dapp)) => {
let (handler, fetch_control) = ContentFetcherHandler::new( let (handler, fetch_control) = ContentFetcherHandler::new(
dapp.url(), dapp.url(),
path,
control, control,
DappInstaller { DappInstaller {
id: content_id.clone(), id: content_id.clone(),
@ -165,6 +167,7 @@ impl<R: URLHint> ContentFetcher<R> {
Some(URLHintResult::Content(content)) => { Some(URLHintResult::Content(content)) => {
let (handler, fetch_control) = ContentFetcherHandler::new( let (handler, fetch_control) = ContentFetcherHandler::new(
content.url, content.url,
path,
control, control,
ContentInstaller { ContentInstaller {
id: content_id.clone(), id: content_id.clone(),
@ -248,43 +251,45 @@ struct ContentInstaller {
id: String, id: String,
mime: String, mime: String,
content_path: PathBuf, content_path: PathBuf,
on_done: Box<Fn(String, Option<LocalPageEndpoint>) + Send>, on_done: Box<Fn(Option<LocalPageEndpoint>) + Send>,
} }
impl ContentValidator for ContentInstaller { impl ContentValidator for ContentInstaller {
type Error = ValidationError; type Error = ValidationError;
fn validate_and_install(&self, path: PathBuf) -> Result<(String, LocalPageEndpoint), ValidationError> { fn validate_and_install(&self, path: PathBuf) -> Result<LocalPageEndpoint, ValidationError> {
// Create dir let validate = || {
try!(fs::create_dir_all(&self.content_path)); // Create dir
try!(fs::create_dir_all(&self.content_path));
// Validate hash // Validate hash
let mut file_reader = io::BufReader::new(try!(fs::File::open(&path))); let mut file_reader = io::BufReader::new(try!(fs::File::open(&path)));
let hash = try!(sha3(&mut file_reader)); let hash = try!(sha3(&mut file_reader));
let id = try!(self.id.as_str().parse().map_err(|_| ValidationError::InvalidContentId)); let id = try!(self.id.as_str().parse().map_err(|_| ValidationError::InvalidContentId));
if id != hash { if id != hash {
return Err(ValidationError::HashMismatch { return Err(ValidationError::HashMismatch {
expected: id, expected: id,
got: hash, got: hash,
}); });
} }
// And prepare path for a file // And prepare path for a file
let filename = path.file_name().expect("We always fetch a file."); let filename = path.file_name().expect("We always fetch a file.");
let mut content_path = self.content_path.clone(); let mut content_path = self.content_path.clone();
content_path.push(&filename); content_path.push(&filename);
if content_path.exists() { if content_path.exists() {
try!(fs::remove_dir_all(&content_path)) try!(fs::remove_dir_all(&content_path))
} }
try!(fs::copy(&path, &content_path)); try!(fs::copy(&path, &content_path));
Ok(LocalPageEndpoint::single_file(content_path, self.mime.clone(), PageCache::Enabled))
};
Ok((self.id.clone(), LocalPageEndpoint::single_file(content_path, self.mime.clone(), PageCache::Enabled))) // Make sure to always call on_done (even in case of errors)!
} let result = validate();
(self.on_done)(result.as_ref().ok().cloned());
fn done(&self, endpoint: Option<LocalPageEndpoint>) { result
(self.on_done)(self.id.clone(), endpoint)
} }
} }
@ -292,7 +297,7 @@ impl ContentValidator for ContentInstaller {
struct DappInstaller { struct DappInstaller {
id: String, id: String,
dapps_path: PathBuf, dapps_path: PathBuf,
on_done: Box<Fn(String, Option<LocalPageEndpoint>) + Send>, on_done: Box<Fn(Option<LocalPageEndpoint>) + Send>,
embeddable_on: Option<(String, u16)>, embeddable_on: Option<(String, u16)>,
} }
@ -331,69 +336,68 @@ impl DappInstaller {
impl ContentValidator for DappInstaller { impl ContentValidator for DappInstaller {
type Error = ValidationError; type Error = ValidationError;
fn validate_and_install(&self, app_path: PathBuf) -> Result<(String, LocalPageEndpoint), ValidationError> { fn validate_and_install(&self, path: PathBuf) -> Result<LocalPageEndpoint, ValidationError> {
trace!(target: "dapps", "Opening dapp bundle at {:?}", app_path); trace!(target: "dapps", "Opening dapp bundle at {:?}", path);
let mut file_reader = io::BufReader::new(try!(fs::File::open(app_path))); let validate = || {
let hash = try!(sha3(&mut file_reader)); let mut file_reader = io::BufReader::new(try!(fs::File::open(path)));
let id = try!(self.id.as_str().parse().map_err(|_| ValidationError::InvalidContentId)); let hash = try!(sha3(&mut file_reader));
if id != hash { let id = try!(self.id.as_str().parse().map_err(|_| ValidationError::InvalidContentId));
return Err(ValidationError::HashMismatch { if id != hash {
expected: id, return Err(ValidationError::HashMismatch {
got: hash, expected: id,
}); got: hash,
} });
let file = file_reader.into_inner(); }
// Unpack archive let file = file_reader.into_inner();
let mut zip = try!(zip::ZipArchive::new(file)); // Unpack archive
// First find manifest file let mut zip = try!(zip::ZipArchive::new(file));
let (mut manifest, manifest_dir) = try!(Self::find_manifest(&mut zip)); // First find manifest file
// Overwrite id to match hash let (mut manifest, manifest_dir) = try!(Self::find_manifest(&mut zip));
manifest.id = self.id.clone(); // Overwrite id to match hash
manifest.id = self.id.clone();
let target = self.dapp_target_path(&manifest); let target = self.dapp_target_path(&manifest);
// Remove old directory // Remove old directory
if target.exists() { if target.exists() {
warn!(target: "dapps", "Overwriting existing dapp: {}", manifest.id); warn!(target: "dapps", "Overwriting existing dapp: {}", manifest.id);
try!(fs::remove_dir_all(target.clone())); try!(fs::remove_dir_all(target.clone()));
} }
// Unpack zip // Unpack zip
for i in 0..zip.len() { for i in 0..zip.len() {
let mut file = try!(zip.by_index(i)); let mut file = try!(zip.by_index(i));
// TODO [todr] Check if it's consistent on windows. // TODO [todr] Check if it's consistent on windows.
let is_dir = file.name().chars().rev().next() == Some('/'); let is_dir = file.name().chars().rev().next() == Some('/');
let file_path = PathBuf::from(file.name()); let file_path = PathBuf::from(file.name());
let location_in_manifest_base = file_path.strip_prefix(&manifest_dir); let location_in_manifest_base = file_path.strip_prefix(&manifest_dir);
// Create files that are inside manifest directory // Create files that are inside manifest directory
if let Ok(location_in_manifest_base) = location_in_manifest_base { if let Ok(location_in_manifest_base) = location_in_manifest_base {
let p = target.join(location_in_manifest_base); let p = target.join(location_in_manifest_base);
// Check if it's a directory // Check if it's a directory
if is_dir { if is_dir {
try!(fs::create_dir_all(p)); try!(fs::create_dir_all(p));
} else { } else {
let mut target = try!(fs::File::create(p)); let mut target = try!(fs::File::create(p));
try!(io::copy(&mut file, &mut target)); try!(io::copy(&mut file, &mut target));
}
} }
} }
}
// Write manifest // Write manifest
let manifest_str = try!(serialize_manifest(&manifest).map_err(ValidationError::ManifestSerialization)); let manifest_str = try!(serialize_manifest(&manifest).map_err(ValidationError::ManifestSerialization));
let manifest_path = target.join(MANIFEST_FILENAME); let manifest_path = target.join(MANIFEST_FILENAME);
let mut manifest_file = try!(fs::File::create(manifest_path)); let mut manifest_file = try!(fs::File::create(manifest_path));
try!(manifest_file.write_all(manifest_str.as_bytes())); try!(manifest_file.write_all(manifest_str.as_bytes()));
// Create endpoint
let endpoint = LocalPageEndpoint::new(target, manifest.clone().into(), PageCache::Enabled, self.embeddable_on.clone());
Ok(endpoint)
};
// Create endpoint let result = validate();
let app = LocalPageEndpoint::new(target, manifest.clone().into(), PageCache::Enabled, self.embeddable_on.clone()); (self.on_done)(result.as_ref().ok().cloned());
result
// Return modified app manifest
Ok((manifest.id.clone(), app))
}
fn done(&self, endpoint: Option<LocalPageEndpoint>) {
(self.on_done)(self.id.clone(), endpoint)
} }
} }

View File

@ -22,35 +22,41 @@ use std::sync::{mpsc, Arc};
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::time::{Instant, Duration}; use std::time::{Instant, Duration};
use util::Mutex; use util::Mutex;
use url::Url;
use fetch::{Client, Fetch, FetchResult}; use fetch::{Client, Fetch, FetchResult};
use hyper::{server, Decoder, Encoder, Next, Method, Control}; use hyper::{server, Decoder, Encoder, Next, Method, Control};
use hyper::net::HttpStream; use hyper::net::HttpStream;
use hyper::uri::RequestUri;
use hyper::status::StatusCode; use hyper::status::StatusCode;
use handlers::{ContentHandler, Redirection, extract_url}; use endpoint::EndpointPath;
use page::LocalPageEndpoint; use handlers::ContentHandler;
use page::{LocalPageEndpoint, PageHandlerWaiting};
const FETCH_TIMEOUT: u64 = 30; const FETCH_TIMEOUT: u64 = 30;
enum FetchState { enum FetchState {
Waiting,
NotStarted(String), NotStarted(String),
Error(ContentHandler), Error(ContentHandler),
InProgress(mpsc::Receiver<FetchResult>), InProgress(mpsc::Receiver<FetchResult>),
Done(String, LocalPageEndpoint, Redirection), Done(LocalPageEndpoint, Box<PageHandlerWaiting>),
}
enum WaitResult {
Error(ContentHandler),
Done(LocalPageEndpoint),
} }
pub trait ContentValidator { pub trait ContentValidator {
type Error: fmt::Debug + fmt::Display; type Error: fmt::Debug + fmt::Display;
fn validate_and_install(&self, app: PathBuf) -> Result<(String, LocalPageEndpoint), Self::Error>; fn validate_and_install(&self, path: PathBuf) -> Result<LocalPageEndpoint, Self::Error>;
fn done(&self, Option<LocalPageEndpoint>);
} }
pub struct FetchControl { pub struct FetchControl {
abort: Arc<AtomicBool>, abort: Arc<AtomicBool>,
listeners: Mutex<Vec<(Control, mpsc::Sender<FetchState>)>>, listeners: Mutex<Vec<(Control, mpsc::Sender<WaitResult>)>>,
deadline: Instant, deadline: Instant,
} }
@ -65,9 +71,10 @@ impl Default for FetchControl {
} }
impl FetchControl { impl FetchControl {
fn notify<F: Fn() -> FetchState>(&self, status: F) { fn notify<F: Fn() -> WaitResult>(&self, status: F) {
let mut listeners = self.listeners.lock(); let mut listeners = self.listeners.lock();
for (control, sender) in listeners.drain(..) { for (control, sender) in listeners.drain(..) {
trace!(target: "dapps", "Resuming request waiting for content...");
if let Err(e) = sender.send(status()) { if let Err(e) = sender.send(status()) {
trace!(target: "dapps", "Waiting listener notification failed: {:?}", e); trace!(target: "dapps", "Waiting listener notification failed: {:?}", e);
} else { } else {
@ -78,9 +85,9 @@ impl FetchControl {
fn set_status(&self, status: &FetchState) { fn set_status(&self, status: &FetchState) {
match *status { match *status {
FetchState::Error(ref handler) => self.notify(|| FetchState::Error(handler.clone())), FetchState::Error(ref handler) => self.notify(|| WaitResult::Error(handler.clone())),
FetchState::Done(ref id, ref endpoint, ref handler) => self.notify(|| FetchState::Done(id.clone(), endpoint.clone(), handler.clone())), FetchState::Done(ref endpoint, _) => self.notify(|| WaitResult::Done(endpoint.clone())),
FetchState::NotStarted(_) | FetchState::InProgress(_) => {}, FetchState::NotStarted(_) | FetchState::InProgress(_) | FetchState::Waiting => {},
} }
} }
@ -88,44 +95,66 @@ impl FetchControl {
self.abort.store(true, Ordering::SeqCst); self.abort.store(true, Ordering::SeqCst);
} }
pub fn to_handler(&self, control: Control) -> Box<server::Handler<HttpStream> + Send> { pub fn to_async_handler(&self, path: EndpointPath, control: Control) -> Box<server::Handler<HttpStream> + Send> {
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
self.listeners.lock().push((control, tx)); self.listeners.lock().push((control, tx));
Box::new(WaitingHandler { Box::new(WaitingHandler {
receiver: rx, receiver: rx,
state: None, state: FetchState::Waiting,
uri: RequestUri::default(),
path: path,
}) })
} }
} }
pub struct WaitingHandler { pub struct WaitingHandler {
receiver: mpsc::Receiver<FetchState>, receiver: mpsc::Receiver<WaitResult>,
state: Option<FetchState>, state: FetchState,
uri: RequestUri,
path: EndpointPath,
} }
impl server::Handler<HttpStream> for WaitingHandler { impl server::Handler<HttpStream> for WaitingHandler {
fn on_request(&mut self, _request: server::Request<HttpStream>) -> Next { fn on_request(&mut self, request: server::Request<HttpStream>) -> Next {
self.uri = request.uri().clone();
Next::wait() Next::wait()
} }
fn on_request_readable(&mut self, _decoder: &mut Decoder<HttpStream>) -> Next { fn on_request_readable(&mut self, decoder: &mut Decoder<HttpStream>) -> Next {
self.state = self.receiver.try_recv().ok(); let result = self.receiver.try_recv().ok();
Next::write() self.state = match result {
Some(WaitResult::Error(handler)) => FetchState::Error(handler),
Some(WaitResult::Done(endpoint)) => {
let mut page_handler = endpoint.to_page_handler(self.path.clone());
page_handler.set_uri(&self.uri);
FetchState::Done(endpoint, page_handler)
},
None => {
warn!("A result for waiting request was not received.");
FetchState::Waiting
},
};
match self.state {
FetchState::Done(_, ref mut handler) => handler.on_request_readable(decoder),
FetchState::Error(ref mut handler) => handler.on_request_readable(decoder),
_ => Next::write(),
}
} }
fn on_response(&mut self, res: &mut server::Response) -> Next { fn on_response(&mut self, res: &mut server::Response) -> Next {
match self.state { match self.state {
Some(FetchState::Done(_, _, ref mut handler)) => handler.on_response(res), FetchState::Done(_, ref mut handler) => handler.on_response(res),
Some(FetchState::Error(ref mut handler)) => handler.on_response(res), FetchState::Error(ref mut handler) => handler.on_response(res),
_ => Next::end(), _ => Next::end(),
} }
} }
fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next { fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next {
match self.state { match self.state {
Some(FetchState::Done(_, _, ref mut handler)) => handler.on_response_writable(encoder), FetchState::Done(_, ref mut handler) => handler.on_response_writable(encoder),
Some(FetchState::Error(ref mut handler)) => handler.on_response_writable(encoder), FetchState::Error(ref mut handler) => handler.on_response_writable(encoder),
_ => Next::end(), _ => Next::end(),
} }
} }
@ -137,29 +166,19 @@ pub struct ContentFetcherHandler<H: ContentValidator> {
status: FetchState, status: FetchState,
client: Option<Client>, client: Option<Client>,
installer: H, installer: H,
request_url: Option<Url>, path: EndpointPath,
uri: RequestUri,
embeddable_on: Option<(String, u16)>, embeddable_on: Option<(String, u16)>,
} }
impl<H: ContentValidator> Drop for ContentFetcherHandler<H> {
fn drop(&mut self) {
let result = match self.status {
FetchState::Done(_, ref result, _) => Some(result.clone()),
_ => None,
};
self.installer.done(result);
}
}
impl<H: ContentValidator> ContentFetcherHandler<H> { impl<H: ContentValidator> ContentFetcherHandler<H> {
pub fn new( pub fn new(
url: String, url: String,
path: EndpointPath,
control: Control, control: Control,
handler: H, handler: H,
embeddable_on: Option<(String, u16)>, embeddable_on: Option<(String, u16)>,
) -> (Self, Arc<FetchControl>) { ) -> (Self, Arc<FetchControl>) {
let fetch_control = Arc::new(FetchControl::default()); let fetch_control = Arc::new(FetchControl::default());
let client = Client::default(); let client = Client::default();
let handler = ContentFetcherHandler { let handler = ContentFetcherHandler {
@ -168,7 +187,8 @@ impl<H: ContentValidator> ContentFetcherHandler<H> {
client: Some(client), client: Some(client),
status: FetchState::NotStarted(url), status: FetchState::NotStarted(url),
installer: handler, installer: handler,
request_url: None, path: path,
uri: RequestUri::default(),
embeddable_on: embeddable_on, embeddable_on: embeddable_on,
}; };
@ -192,7 +212,6 @@ impl<H: ContentValidator> ContentFetcherHandler<H> {
impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<H> { impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<H> {
fn on_request(&mut self, request: server::Request<HttpStream>) -> Next { fn on_request(&mut self, request: server::Request<HttpStream>) -> Next {
self.request_url = extract_url(&request);
let status = if let FetchState::NotStarted(ref url) = self.status { let status = if let FetchState::NotStarted(ref url) = self.status {
Some(match *request.method() { Some(match *request.method() {
// Start fetching content // Start fetching content
@ -205,8 +224,8 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<
Ok(receiver) => FetchState::InProgress(receiver), Ok(receiver) => FetchState::InProgress(receiver),
Err(e) => FetchState::Error(ContentHandler::error( Err(e) => FetchState::Error(ContentHandler::error(
StatusCode::BadGateway, StatusCode::BadGateway,
"Unable To Start Dapp Download", "Unable To Start Content Download",
"Could not initialize download of the dapp. It might be a problem with the remote server.", "Could not initialize download of the content. It might be a problem with the remote server.",
Some(&format!("{}", e)), Some(&format!("{}", e)),
self.embeddable_on.clone(), self.embeddable_on.clone(),
)), )),
@ -227,6 +246,7 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<
self.fetch_control.set_status(&status); self.fetch_control.set_status(&status);
self.status = status; self.status = status;
} }
self.uri = request.uri().clone();
Next::read() Next::read()
} }
@ -266,11 +286,10 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<
self.embeddable_on.clone(), self.embeddable_on.clone(),
)) ))
}, },
Ok((id, result)) => { Ok(endpoint) => {
let url: String = self.request_url.take() let mut handler = endpoint.to_page_handler(self.path.clone());
.map(|url| url.raw.into_string()) handler.set_uri(&self.uri);
.expect("Request URL always read in on_request; qed"); FetchState::Done(endpoint, handler)
FetchState::Done(id, result, Redirection::new(&url))
}, },
}; };
// Remove temporary zip file // Remove temporary zip file
@ -306,7 +325,7 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<
fn on_response(&mut self, res: &mut server::Response) -> Next { fn on_response(&mut self, res: &mut server::Response) -> Next {
match self.status { match self.status {
FetchState::Done(_, _, ref mut handler) => handler.on_response(res), FetchState::Done(_, ref mut handler) => handler.on_response(res),
FetchState::Error(ref mut handler) => handler.on_response(res), FetchState::Error(ref mut handler) => handler.on_response(res),
_ => Next::end(), _ => Next::end(),
} }
@ -314,7 +333,7 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<
fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next { fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next {
match self.status { match self.status {
FetchState::Done(_, _, ref mut handler) => handler.on_response_writable(encoder), FetchState::Done(_, ref mut handler) => handler.on_response_writable(encoder),
FetchState::Error(ref mut handler) => handler.on_response_writable(encoder), FetchState::Error(ref mut handler) => handler.on_response_writable(encoder),
_ => Next::end(), _ => Next::end(),
} }

View File

@ -57,7 +57,7 @@ extern crate mime_guess;
extern crate rustc_serialize; extern crate rustc_serialize;
extern crate ethcore_rpc; extern crate ethcore_rpc;
extern crate ethcore_util as util; extern crate ethcore_util as util;
extern crate ethcore_hash_fetch as hash_fetch; extern crate parity_hash_fetch as hash_fetch;
extern crate linked_hash_map; extern crate linked_hash_map;
extern crate fetch; extern crate fetch;
extern crate parity_dapps_glue as parity_dapps; extern crate parity_dapps_glue as parity_dapps;

View File

@ -83,13 +83,19 @@ impl Default for PageCache {
} }
} }
/// A generic type for `PageHandler` allowing to set the URL.
/// Used by dapps fetching to set the URL after the content was downloaded.
pub trait PageHandlerWaiting: server::Handler<HttpStream> + Send {
fn set_uri(&mut self, uri: &RequestUri);
}
/// A handler for a single webapp. /// A handler for a single webapp.
/// Resolves correct paths and serves as a plumbing code between /// Resolves correct paths and serves as a plumbing code between
/// hyper server and dapp. /// hyper server and dapp.
pub struct PageHandler<T: Dapp> { pub struct PageHandler<T: Dapp> {
/// A Dapp. /// A Dapp.
pub app: T, pub app: T,
/// File currently being served (or `None` if file does not exist). /// File currently being served
pub file: ServedFile<T>, pub file: ServedFile<T>,
/// Optional prefix to strip from path. /// Optional prefix to strip from path.
pub prefix: Option<String>, pub prefix: Option<String>,
@ -101,6 +107,21 @@ pub struct PageHandler<T: Dapp> {
pub cache: PageCache, pub cache: PageCache,
} }
impl<T: Dapp> PageHandlerWaiting for PageHandler<T> {
fn set_uri(&mut self, uri: &RequestUri) {
trace!(target: "dapps", "Setting URI: {:?}", uri);
self.file = match *uri {
RequestUri::AbsolutePath { ref path, .. } => {
self.app.file(&self.extract_path(path))
},
RequestUri::AbsoluteUri(ref url) => {
self.app.file(&self.extract_path(url.path()))
},
_ => None,
}.map_or_else(|| ServedFile::new(self.safe_to_embed_on.clone()), |f| ServedFile::File(f));
}
}
impl<T: Dapp> PageHandler<T> { impl<T: Dapp> PageHandler<T> {
fn extract_path(&self, path: &str) -> String { fn extract_path(&self, path: &str) -> String {
let app_id = &self.path.app_id; let app_id = &self.path.app_id;
@ -124,15 +145,7 @@ impl<T: Dapp> PageHandler<T> {
impl<T: Dapp> server::Handler<HttpStream> for PageHandler<T> { impl<T: Dapp> server::Handler<HttpStream> for PageHandler<T> {
fn on_request(&mut self, req: server::Request<HttpStream>) -> Next { fn on_request(&mut self, req: server::Request<HttpStream>) -> Next {
self.file = match *req.uri() { self.set_uri(req.uri());
RequestUri::AbsolutePath { ref path, .. } => {
self.app.file(&self.extract_path(path))
},
RequestUri::AbsoluteUri(ref url) => {
self.app.file(&self.extract_path(url.path()))
},
_ => None,
}.map_or_else(|| ServedFile::new(self.safe_to_embed_on.clone()), |f| ServedFile::File(f));
Next::write() Next::write()
} }

View File

@ -18,7 +18,7 @@ use mime_guess;
use std::io::{Seek, Read, SeekFrom}; use std::io::{Seek, Read, SeekFrom};
use std::fs; use std::fs;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use page::handler::{self, PageCache}; use page::handler::{self, PageCache, PageHandlerWaiting};
use endpoint::{Endpoint, EndpointInfo, EndpointPath, Handler}; use endpoint::{Endpoint, EndpointInfo, EndpointPath, Handler};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -54,6 +54,36 @@ impl LocalPageEndpoint {
pub fn path(&self) -> PathBuf { pub fn path(&self) -> PathBuf {
self.path.clone() self.path.clone()
} }
fn page_handler_with_mime(&self, path: EndpointPath, mime: &str) -> handler::PageHandler<LocalSingleFile> {
handler::PageHandler {
app: LocalSingleFile { path: self.path.clone(), mime: mime.into() },
prefix: None,
path: path,
file: handler::ServedFile::new(None),
safe_to_embed_on: self.embeddable_on.clone(),
cache: self.cache,
}
}
fn page_handler(&self, path: EndpointPath) -> handler::PageHandler<LocalDapp> {
handler::PageHandler {
app: LocalDapp { path: self.path.clone() },
prefix: None,
path: path,
file: handler::ServedFile::new(None),
safe_to_embed_on: self.embeddable_on.clone(),
cache: self.cache,
}
}
pub fn to_page_handler(&self, path: EndpointPath) -> Box<PageHandlerWaiting> {
if let Some(ref mime) = self.mime {
Box::new(self.page_handler_with_mime(path, mime))
} else {
Box::new(self.page_handler(path))
}
}
} }
impl Endpoint for LocalPageEndpoint { impl Endpoint for LocalPageEndpoint {
@ -63,23 +93,9 @@ impl Endpoint for LocalPageEndpoint {
fn to_handler(&self, path: EndpointPath) -> Box<Handler> { fn to_handler(&self, path: EndpointPath) -> Box<Handler> {
if let Some(ref mime) = self.mime { if let Some(ref mime) = self.mime {
Box::new(handler::PageHandler { Box::new(self.page_handler_with_mime(path, mime))
app: LocalSingleFile { path: self.path.clone(), mime: mime.clone() },
prefix: None,
path: path,
file: handler::ServedFile::new(None),
safe_to_embed_on: self.embeddable_on.clone(),
cache: self.cache,
})
} else { } else {
Box::new(handler::PageHandler { Box::new(self.page_handler(path))
app: LocalDapp { path: self.path.clone() },
prefix: None,
path: path,
file: handler::ServedFile::new(None),
safe_to_embed_on: self.embeddable_on.clone(),
cache: self.cache,
})
} }
} }
} }

View File

@ -21,5 +21,5 @@ mod handler;
pub use self::local::LocalPageEndpoint; pub use self::local::LocalPageEndpoint;
pub use self::builtin::PageEndpoint; pub use self::builtin::PageEndpoint;
pub use self::handler::PageCache; pub use self::handler::{PageCache, PageHandlerWaiting};

View File

@ -65,7 +65,7 @@ fn init_logger() {
if let Ok(log) = env::var("RUST_LOG") { if let Ok(log) = env::var("RUST_LOG") {
let mut builder = LogBuilder::new(); let mut builder = LogBuilder::new();
builder.parse(&log); builder.parse(&log);
builder.init().expect("Logger is initialized only once."); let _ = builder.init(); // ignore errors since ./test.sh will call this multiple times.
} }
} }

View File

@ -15,7 +15,7 @@ clippy = { version = "0.0.103", optional = true}
ethcore-devtools = { path = "../devtools" } ethcore-devtools = { path = "../devtools" }
ethcore-ipc = { path = "../ipc/rpc" } ethcore-ipc = { path = "../ipc/rpc" }
rocksdb = { git = "https://github.com/ethcore/rust-rocksdb" } rocksdb = { git = "https://github.com/ethcore/rust-rocksdb" }
semver = "0.2" semver = "0.5"
ethcore-ipc-nano = { path = "../ipc/nano" } ethcore-ipc-nano = { path = "../ipc/nano" }
nanomsg = { git = "https://github.com/ethcore/nanomsg.rs.git" } nanomsg = { git = "https://github.com/ethcore/nanomsg.rs.git" }
crossbeam = "0.2" crossbeam = "0.2"

View File

@ -270,8 +270,7 @@ impl DatabaseService for Database {
Ok(next_iterator) Ok(next_iterator)
} }
fn iter_next(&self, handle: IteratorHandle) -> Option<KeyValue> fn iter_next(&self, handle: IteratorHandle) -> Option<KeyValue> {
{
let mut iterators = self.iterators.write(); let mut iterators = self.iterators.write();
let mut iterator = match iterators.get_mut(&handle) { let mut iterator = match iterators.get_mut(&handle) {
Some(some_iterator) => some_iterator, Some(some_iterator) => some_iterator,

View File

@ -21,7 +21,7 @@ crossbeam = "0.2.9"
lazy_static = "0.2" lazy_static = "0.2"
bloomchain = "0.1" bloomchain = "0.1"
rayon = "0.4.2" rayon = "0.4.2"
semver = "0.2" semver = "0.5"
bit-set = "0.4" bit-set = "0.4"
time = "0.1" time = "0.1"
rand = "0.3" rand = "0.3"
@ -42,6 +42,7 @@ ethcore-ipc-nano = { path = "../ipc/nano" }
rlp = { path = "../util/rlp" } rlp = { path = "../util/rlp" }
lru-cache = "0.1.0" lru-cache = "0.1.0"
ethcore-bloom-journal = { path = "../util/bloom" } ethcore-bloom-journal = { path = "../util/bloom" }
ethabi = "0.2.2"
[dependencies.hyper] [dependencies.hyper]
git = "https://github.com/ethcore/hyper" git = "https://github.com/ethcore/hyper"

View File

@ -24,7 +24,7 @@ use ethcore::service::ClientIoMessage;
use ethcore::block_import_error::BlockImportError; use ethcore::block_import_error::BlockImportError;
use ethcore::block_status::BlockStatus; use ethcore::block_status::BlockStatus;
use ethcore::verification::queue::{HeaderQueue, QueueInfo}; use ethcore::verification::queue::{HeaderQueue, QueueInfo};
use ethcore::transaction::SignedTransaction; use ethcore::transaction::{SignedTransaction, PendingTransaction};
use ethcore::blockchain_info::BlockChainInfo; use ethcore::blockchain_info::BlockChainInfo;
use io::IoChannel; use io::IoChannel;
@ -90,31 +90,31 @@ impl Provider for Client {
None None
} }
fn block_headers(&self, _req: request::Headers) -> Vec<Bytes> { fn block_header(&self, _id: BlockId) -> Option<Bytes> {
None
}
fn block_body(&self, _id: BlockId) -> Option<Bytes> {
None
}
fn block_receipts(&self, _hash: &H256) -> Option<Bytes> {
None
}
fn state_proof(&self, _req: request::StateProof) -> Vec<Bytes> {
Vec::new() Vec::new()
} }
fn block_bodies(&self, _req: request::Bodies) -> Vec<Bytes> { fn contract_code(&self, _req: request::ContractCode) -> Bytes {
Vec::new() Vec::new()
} }
fn receipts(&self, _req: request::Receipts) -> Vec<Bytes> { fn header_proof(&self, _req: request::HeaderProof) -> Option<(Bytes, Vec<Bytes>)> {
Vec::new() None
} }
fn proofs(&self, _req: request::StateProofs) -> Vec<Bytes> { fn ready_transactions(&self) -> Vec<PendingTransaction> {
Vec::new()
}
fn contract_code(&self, _req: request::ContractCodes) -> Vec<Bytes> {
Vec::new()
}
fn header_proofs(&self, _req: request::HeaderProofs) -> Vec<Bytes> {
Vec::new()
}
fn pending_transactions(&self) -> Vec<SignedTransaction> {
Vec::new() Vec::new()
} }
} }

View File

@ -956,7 +956,7 @@ impl LightProtocol {
let max_cost = try!(peer.deduct_max(&self.flow_params, request::Kind::Codes, req.code_requests.len())); let max_cost = try!(peer.deduct_max(&self.flow_params, request::Kind::Codes, req.code_requests.len()));
let response = self.provider.contract_code(req); let response = self.provider.contract_codes(req);
let response_len = response.iter().filter(|x| !x.is_empty()).count(); let response_len = response.iter().filter(|x| !x.is_empty()).count();
let actual_cost = self.flow_params.compute_cost(request::Kind::Codes, response_len); let actual_cost = self.flow_params.compute_cost(request::Kind::Codes, response_len);
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost."); assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");

View File

@ -20,7 +20,7 @@
use ethcore::blockchain_info::BlockChainInfo; use ethcore::blockchain_info::BlockChainInfo;
use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient}; use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient};
use ethcore::ids::BlockId; use ethcore::ids::BlockId;
use ethcore::transaction::SignedTransaction; use ethcore::transaction::PendingTransaction;
use network::{PeerId, NodeId}; use network::{PeerId, NodeId};
use net::buffer_flow::FlowParams; use net::buffer_flow::FlowParams;
@ -94,83 +94,40 @@ impl Provider for TestProvider {
None None
} }
fn block_headers(&self, req: request::Headers) -> Vec<Bytes> { fn block_header(&self, id: BlockId) -> Option<Bytes> {
use request::HashOrNumber; self.0.client.block_header(id)
use ethcore::views::HeaderView; }
let best_num = self.chain_info().best_block_number; fn block_body(&self, id: BlockId) -> Option<Bytes> {
let start_num = match req.start { self.0.client.block_body(id)
HashOrNumber::Number(start_num) => start_num, }
HashOrNumber::Hash(hash) => match self.0.client.block_header(BlockId::Hash(hash)) {
None => {
return Vec::new();
}
Some(header) => {
let num = HeaderView::new(&header).number();
if req.max == 1 || self.0.client.block_hash(BlockId::Number(num)) != Some(hash) {
// Non-canonical header or single header requested.
return vec![header];
}
num fn block_receipts(&self, hash: &H256) -> Option<Bytes> {
} self.0.client.block_receipts(&hash)
}
fn state_proof(&self, req: request::StateProof) -> Vec<Bytes> {
match req.key2 {
Some(_) => vec![::util::sha3::SHA3_NULL_RLP.to_vec()],
None => {
// sort of a leaf node
let mut stream = RlpStream::new_list(2);
stream.append(&req.key1).append_empty_data();
vec![stream.out()]
} }
}; }
(0u64..req.max as u64)
.map(|x: u64| x.saturating_mul(req.skip + 1))
.take_while(|x| if req.reverse { x < &start_num } else { best_num - start_num >= *x })
.map(|x| if req.reverse { start_num - x } else { start_num + x })
.map(|x| self.0.client.block_header(BlockId::Number(x)))
.take_while(|x| x.is_some())
.flat_map(|x| x)
.collect()
} }
fn block_bodies(&self, req: request::Bodies) -> Vec<Bytes> { fn contract_code(&self, req: request::ContractCode) -> Bytes {
req.block_hashes.into_iter() req.account_key.iter().chain(req.account_key.iter()).cloned().collect()
.map(|hash| self.0.client.block_body(BlockId::Hash(hash)))
.map(|body| body.unwrap_or_else(|| ::rlp::EMPTY_LIST_RLP.to_vec()))
.collect()
} }
fn receipts(&self, req: request::Receipts) -> Vec<Bytes> { fn header_proof(&self, _req: request::HeaderProof) -> Option<(Bytes, Vec<Bytes>)> {
req.block_hashes.into_iter() None
.map(|hash| self.0.client.block_receipts(&hash))
.map(|receipts| receipts.unwrap_or_else(|| ::rlp::EMPTY_LIST_RLP.to_vec()))
.collect()
} }
fn proofs(&self, req: request::StateProofs) -> Vec<Bytes> { fn ready_transactions(&self) -> Vec<PendingTransaction> {
req.requests.into_iter() self.0.client.ready_transactions()
.map(|req| {
match req.key2 {
Some(_) => ::util::sha3::SHA3_NULL_RLP.to_vec(),
None => {
// sort of a leaf node
let mut stream = RlpStream::new_list(2);
stream.append(&req.key1).append_empty_data();
stream.out()
}
}
})
.collect()
}
fn contract_code(&self, req: request::ContractCodes) -> Vec<Bytes> {
req.code_requests.into_iter()
.map(|req| {
req.account_key.iter().chain(req.account_key.iter()).cloned().collect()
})
.collect()
}
fn header_proofs(&self, req: request::HeaderProofs) -> Vec<Bytes> {
req.requests.into_iter().map(|_| ::rlp::EMPTY_LIST_RLP.to_vec()).collect()
}
fn pending_transactions(&self) -> Vec<SignedTransaction> {
self.0.client.pending_transactions()
} }
} }
@ -455,8 +412,8 @@ fn get_state_proofs() {
let request_body = encode_request(&request, req_id); let request_body = encode_request(&request, req_id);
let response = { let response = {
let proofs = vec![ let proofs = vec![
{ let mut stream = RlpStream::new_list(2); stream.append(&key1).append_empty_data(); stream.out() }, { let mut stream = RlpStream::new_list(2); stream.append(&key1).append_empty_data(); vec![stream.out()] },
::util::sha3::SHA3_NULL_RLP.to_vec(), vec![::util::sha3::SHA3_NULL_RLP.to_vec()],
]; ];
let new_buf = *flow_params.limit() - flow_params.compute_cost(request::Kind::StateProofs, 2); let new_buf = *flow_params.limit() - flow_params.compute_cost(request::Kind::StateProofs, 2);
@ -465,7 +422,10 @@ fn get_state_proofs() {
response_stream.append(&req_id).append(&new_buf).begin_list(2); response_stream.append(&req_id).append(&new_buf).begin_list(2);
for proof in proofs { for proof in proofs {
response_stream.append_raw(&proof, 1); response_stream.begin_list(proof.len());
for node in proof {
response_stream.append_raw(&node, 1);
}
} }
response_stream.out() response_stream.out()

View File

@ -19,7 +19,7 @@
use ethcore::blockchain_info::BlockChainInfo; use ethcore::blockchain_info::BlockChainInfo;
use ethcore::client::{BlockChainClient, ProvingBlockChainClient}; use ethcore::client::{BlockChainClient, ProvingBlockChainClient};
use ethcore::transaction::SignedTransaction; use ethcore::transaction::PendingTransaction;
use ethcore::ids::BlockId; use ethcore::ids::BlockId;
use util::{Bytes, H256}; use util::{Bytes, H256};
@ -52,54 +52,12 @@ pub trait Provider: Send + Sync {
/// ///
/// The returned vector may have any length in the range [0, `max`], but the /// The returned vector may have any length in the range [0, `max`], but the
/// results within must adhere to the `skip` and `reverse` parameters. /// results within must adhere to the `skip` and `reverse` parameters.
fn block_headers(&self, req: request::Headers) -> Vec<Bytes>;
/// Provide as many as possible of the requested blocks (minus the headers) encoded
/// in RLP format.
fn block_bodies(&self, req: request::Bodies) -> Vec<Bytes>;
/// Provide the receipts as many as possible of the requested blocks.
/// Returns a vector of RLP-encoded lists of receipts.
fn receipts(&self, req: request::Receipts) -> Vec<Bytes>;
/// Provide a set of merkle proofs, as requested. Each request is a
/// block hash and request parameters.
///
/// Returns a vector of RLP-encoded lists satisfying the requests.
fn proofs(&self, req: request::StateProofs) -> Vec<Bytes>;
/// Provide contract code for the specified (block_hash, account_hash) pairs.
/// Each item in the resulting vector is either the raw bytecode or empty.
fn contract_code(&self, req: request::ContractCodes) -> Vec<Bytes>;
/// Provide header proofs from the Canonical Hash Tries as well as the headers
/// they correspond to -- each element in the returned vector is a 2-tuple.
/// The first element is a block header and the second a merkle proof of
/// the header in a requested CHT.
fn header_proofs(&self, req: request::HeaderProofs) -> Vec<Bytes>;
/// Provide pending transactions.
fn pending_transactions(&self) -> Vec<SignedTransaction>;
}
// Implementation of a light client data provider for a client.
impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
fn chain_info(&self) -> BlockChainInfo {
BlockChainClient::chain_info(self)
}
fn reorg_depth(&self, a: &H256, b: &H256) -> Option<u64> {
self.tree_route(a, b).map(|route| route.index as u64)
}
fn earliest_state(&self) -> Option<u64> {
Some(self.pruning_info().earliest_state)
}
fn block_headers(&self, req: request::Headers) -> Vec<Bytes> { fn block_headers(&self, req: request::Headers) -> Vec<Bytes> {
use request::HashOrNumber; use request::HashOrNumber;
use ethcore::views::HeaderView; use ethcore::views::HeaderView;
if req.max == 0 { return Vec::new() }
let best_num = self.chain_info().best_block_number; let best_num = self.chain_info().best_block_number;
let start_num = match req.start { let start_num = match req.start {
HashOrNumber::Number(start_num) => start_num, HashOrNumber::Number(start_num) => start_num,
@ -110,7 +68,10 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
} }
Some(header) => { Some(header) => {
let num = HeaderView::new(&header).number(); let num = HeaderView::new(&header).number();
if req.max == 1 || self.block_hash(BlockId::Number(num)) != Some(hash) { let canon_hash = self.block_header(BlockId::Number(num))
.map(|h| HeaderView::new(&h).hash());
if req.max == 1 || canon_hash != Some(hash) {
// Non-canonical header or single header requested. // Non-canonical header or single header requested.
return vec![header]; return vec![header];
} }
@ -130,6 +91,11 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
.collect() .collect()
} }
/// Get a block header by id.
fn block_header(&self, id: BlockId) -> Option<Bytes>;
/// Provide as many as possible of the requested blocks (minus the headers) encoded
/// in RLP format.
fn block_bodies(&self, req: request::Bodies) -> Vec<Bytes> { fn block_bodies(&self, req: request::Bodies) -> Vec<Bytes> {
req.block_hashes.into_iter() req.block_hashes.into_iter()
.map(|hash| self.block_body(BlockId::Hash(hash))) .map(|hash| self.block_body(BlockId::Hash(hash)))
@ -137,6 +103,11 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
.collect() .collect()
} }
/// Get a block body by id.
fn block_body(&self, id: BlockId) -> Option<Bytes>;
/// Provide the receipts as many as possible of the requested blocks.
/// Returns a vector of RLP-encoded lists of receipts.
fn receipts(&self, req: request::Receipts) -> Vec<Bytes> { fn receipts(&self, req: request::Receipts) -> Vec<Bytes> {
req.block_hashes.into_iter() req.block_hashes.into_iter()
.map(|hash| self.block_receipts(&hash)) .map(|hash| self.block_receipts(&hash))
@ -144,16 +115,20 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
.collect() .collect()
} }
/// Get a block's receipts as an RLP-encoded list by block hash.
fn block_receipts(&self, hash: &H256) -> Option<Bytes>;
/// Provide a set of merkle proofs, as requested. Each request is a
/// block hash and request parameters.
///
/// Returns a vector of RLP-encoded lists satisfying the requests.
fn proofs(&self, req: request::StateProofs) -> Vec<Bytes> { fn proofs(&self, req: request::StateProofs) -> Vec<Bytes> {
use rlp::{RlpStream, Stream}; use rlp::{RlpStream, Stream};
let mut results = Vec::with_capacity(req.requests.len()); let mut results = Vec::with_capacity(req.requests.len());
for request in req.requests { for request in req.requests {
let proof = match request.key2 { let proof = self.state_proof(request);
Some(key2) => self.prove_storage(request.key1, key2, request.from_level, BlockId::Hash(request.block)),
None => self.prove_account(request.key1, request.from_level, BlockId::Hash(request.block)),
};
let mut stream = RlpStream::new_list(proof.len()); let mut stream = RlpStream::new_list(proof.len());
for node in proof { for node in proof {
@ -166,19 +141,97 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
results results
} }
fn contract_code(&self, req: request::ContractCodes) -> Vec<Bytes> { /// Get a state proof from a request. Each proof should be a vector
/// of rlp-encoded trie nodes, in ascending order by distance from the root.
fn state_proof(&self, req: request::StateProof) -> Vec<Bytes>;
/// Provide contract code for the specified (block_hash, account_hash) pairs.
/// Each item in the resulting vector is either the raw bytecode or empty.
fn contract_codes(&self, req: request::ContractCodes) -> Vec<Bytes> {
req.code_requests.into_iter() req.code_requests.into_iter()
.map(|req| { .map(|req| self.contract_code(req))
self.code_by_hash(req.account_key, BlockId::Hash(req.block_hash)) .collect()
}
/// Get contract code by request. Either the raw bytecode or empty.
fn contract_code(&self, req: request::ContractCode) -> Bytes;
/// Provide header proofs from the Canonical Hash Tries as well as the headers
/// they correspond to -- each element in the returned vector is a 2-tuple.
/// The first element is a block header and the second a merkle proof of
/// the header in a requested CHT.
fn header_proofs(&self, req: request::HeaderProofs) -> Vec<Bytes> {
use rlp::{self, RlpStream, Stream};
req.requests.into_iter()
.map(|req| self.header_proof(req))
.map(|maybe_proof| match maybe_proof {
None => rlp::EMPTY_LIST_RLP.to_vec(),
Some((header, proof)) => {
let mut stream = RlpStream::new_list(2);
stream.append_raw(&header, 1).begin_list(proof.len());
for node in proof {
stream.append_raw(&node, 1);
}
stream.out()
}
}) })
.collect() .collect()
} }
fn header_proofs(&self, req: request::HeaderProofs) -> Vec<Bytes> { /// Provide a header proof from a given Canonical Hash Trie as well as the
req.requests.into_iter().map(|_| ::rlp::EMPTY_LIST_RLP.to_vec()).collect() /// corresponding header. The first element is the block header and the
/// second is a merkle proof of the CHT.
fn header_proof(&self, req: request::HeaderProof) -> Option<(Bytes, Vec<Bytes>)>;
/// Provide pending transactions.
fn ready_transactions(&self) -> Vec<PendingTransaction>;
}
// Implementation of a light client data provider for a client.
impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
fn chain_info(&self) -> BlockChainInfo {
BlockChainClient::chain_info(self)
} }
fn pending_transactions(&self) -> Vec<SignedTransaction> { fn reorg_depth(&self, a: &H256, b: &H256) -> Option<u64> {
BlockChainClient::pending_transactions(self) self.tree_route(a, b).map(|route| route.index as u64)
}
fn earliest_state(&self) -> Option<u64> {
Some(self.pruning_info().earliest_state)
}
fn block_header(&self, id: BlockId) -> Option<Bytes> {
BlockChainClient::block_header(self, id)
}
fn block_body(&self, id: BlockId) -> Option<Bytes> {
BlockChainClient::block_body(self, id)
}
fn block_receipts(&self, hash: &H256) -> Option<Bytes> {
BlockChainClient::block_receipts(self, hash)
}
fn state_proof(&self, req: request::StateProof) -> Vec<Bytes> {
match req.key2 {
Some(key2) => self.prove_storage(req.key1, key2, req.from_level, BlockId::Hash(req.block)),
None => self.prove_account(req.key1, req.from_level, BlockId::Hash(req.block)),
}
}
fn contract_code(&self, req: request::ContractCode) -> Bytes {
self.code_by_hash(req.account_key, BlockId::Hash(req.block_hash))
}
fn header_proof(&self, _req: request::HeaderProof) -> Option<(Bytes, Vec<Bytes>)> {
None
}
fn ready_transactions(&self) -> Vec<PendingTransaction> {
BlockChainClient::ready_transactions(self)
} }
} }

View File

@ -1,7 +1,7 @@
{ {
"name": "TestAuthorityRound", "name": "TestAuthorityRound",
"engine": { "engine": {
"AuthorityRound": { "authorityRound": {
"params": { "params": {
"gasLimitBoundDivisor": "0x0400", "gasLimitBoundDivisor": "0x0400",
"stepDuration": 1, "stepDuration": 1,
@ -21,7 +21,7 @@
}, },
"genesis": { "genesis": {
"seal": { "seal": {
"authority_round": { "authorityRound": {
"step": "0x0", "step": "0x0",
"signature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" "signature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
} }

View File

@ -1,7 +1,7 @@
{ {
"name": "TestBasicAuthority", "name": "TestBasicAuthority",
"engine": { "engine": {
"BasicAuthority": { "basicAuthority": {
"params": { "params": {
"gasLimitBoundDivisor": "0x0400", "gasLimitBoundDivisor": "0x0400",
"durationLimit": "0x0d", "durationLimit": "0x0d",

View File

@ -1,6 +1,6 @@
{ {
"name": "Ethereum Classic", "name": "Ethereum Classic",
"forkName": "classic", "dataDir": "classic",
"engine": { "engine": {
"Ethash": { "Ethash": {
"params": { "params": {

View File

@ -1,6 +1,6 @@
{ {
"name": "Expanse", "name": "Expanse",
"forkName": "expanse", "dataDir": "expanse",
"engine": { "engine": {
"Ethash": { "Ethash": {
"params": { "params": {

View File

@ -1,5 +1,6 @@
{ {
"name": "Frontier/Homestead", "name": "Frontier/Homestead",
"dataDir": "ethereum",
"engine": { "engine": {
"Ethash": { "Ethash": {
"params": { "params": {

View File

@ -1,5 +1,6 @@
{ {
"name": "Morden", "name": "Morden",
"dataDir": "test",
"engine": { "engine": {
"Ethash": { "Ethash": {
"params": { "params": {

View File

@ -1,5 +1,6 @@
{ {
"name": "Ropsten", "name": "Ropsten",
"dataDir": "test",
"engine": { "engine": {
"Ethash": { "Ethash": {
"params": { "params": {
@ -14,7 +15,8 @@
"eip155Transition": 10, "eip155Transition": 10,
"eip160Transition": 10, "eip160Transition": 10,
"eip161abcTransition": 10, "eip161abcTransition": 10,
"eip161dTransition": 10 "eip161dTransition": 10,
"maxCodeSize": 24576
} }
} }
}, },

View File

@ -1,7 +1,7 @@
{ {
"name": "DevelopmentChain", "name": "DevelopmentChain",
"engine": { "engine": {
"InstantSeal": null "instantSeal": null
}, },
"params": { "params": {
"accountStartNonce": "0x0", "accountStartNonce": "0x0",

View File

@ -1,7 +1,7 @@
{ {
"name": "Morden", "name": "Morden",
"engine": { "engine": {
"Null": null "null": null
}, },
"params": { "params": {
"accountStartNonce": "0x0", "accountStartNonce": "0x0",

View File

@ -1,7 +1,7 @@
{ {
"name": "Morden", "name": "Morden",
"engine": { "engine": {
"Null": null "null": null
}, },
"params": { "params": {
"accountStartNonce": "0x0", "accountStartNonce": "0x0",

View File

@ -1,7 +1,7 @@
{ {
"name": "TestBFT", "name": "TestBFT",
"engine": { "engine": {
"Tendermint": { "tendermint": {
"params": { "params": {
"gasLimitBoundDivisor": "0x0400", "gasLimitBoundDivisor": "0x0400",
"authorities" : [ "authorities" : [
@ -19,8 +19,12 @@
}, },
"genesis": { "genesis": {
"seal": { "seal": {
"generic": { "tendermint": {
"rlp": "f88980b8410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f843b8410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" "round": "0x0",
"proposal": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"precommits": [
"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
]
} }
}, },
"difficulty": "0x20000", "difficulty": "0x20000",

View File

@ -18,7 +18,7 @@
mod stores; mod stores;
use self::stores::{AddressBook, DappsSettingsStore}; use self::stores::{AddressBook, DappsSettingsStore, NewDappsPolicy};
use std::fmt; use std::fmt;
use std::collections::HashMap; use std::collections::HashMap;
@ -156,10 +156,49 @@ impl AccountProvider {
Ok(accounts) Ok(accounts)
} }
/// Sets a whitelist of accounts exposed for unknown dapps.
/// `None` means that all accounts will be visible.
pub fn set_new_dapps_whitelist(&self, accounts: Option<Vec<Address>>) -> Result<(), Error> {
self.dapps_settings.write().set_policy(match accounts {
None => NewDappsPolicy::AllAccounts,
Some(accounts) => NewDappsPolicy::Whitelist(accounts),
});
Ok(())
}
/// Gets a whitelist of accounts exposed for unknown dapps.
/// `None` means that all accounts will be visible.
pub fn new_dapps_whitelist(&self) -> Result<Option<Vec<Address>>, Error> {
Ok(match self.dapps_settings.read().policy() {
NewDappsPolicy::AllAccounts => None,
NewDappsPolicy::Whitelist(accounts) => Some(accounts),
})
}
/// Gets a list of dapps recently requesting accounts.
pub fn recent_dapps(&self) -> Result<Vec<DappId>, Error> {
Ok(self.dapps_settings.read().recent_dapps())
}
/// Marks dapp as recently used.
pub fn note_dapp_used(&self, dapp: DappId) -> Result<(), Error> {
let mut dapps = self.dapps_settings.write();
dapps.mark_dapp_used(dapp.clone());
Ok(())
}
/// Gets addresses visile for dapp. /// Gets addresses visile for dapp.
pub fn dapps_addresses(&self, dapp: DappId) -> Result<Vec<Address>, Error> { pub fn dapps_addresses(&self, dapp: DappId) -> Result<Vec<Address>, Error> {
let accounts = self.dapps_settings.read().get(); let dapps = self.dapps_settings.read();
Ok(accounts.get(&dapp).map(|settings| settings.accounts.clone()).unwrap_or_else(Vec::new))
let accounts = dapps.settings().get(&dapp).map(|settings| settings.accounts.clone());
match accounts {
Some(accounts) => Ok(accounts),
None => match dapps.policy() {
NewDappsPolicy::AllAccounts => self.accounts(),
NewDappsPolicy::Whitelist(accounts) => Ok(accounts),
}
}
} }
/// Sets addresses visile for dapp. /// Sets addresses visile for dapp.
@ -423,6 +462,8 @@ mod tests {
// given // given
let ap = AccountProvider::transient_provider(); let ap = AccountProvider::transient_provider();
let app = "app1".to_owned(); let app = "app1".to_owned();
// set `AllAccounts` policy
ap.set_new_dapps_whitelist(None).unwrap();
// when // when
ap.set_dapps_addresses(app.clone(), vec![1.into(), 2.into()]).unwrap(); ap.set_dapps_addresses(app.clone(), vec![1.into(), 2.into()]).unwrap();
@ -430,4 +471,23 @@ mod tests {
// then // then
assert_eq!(ap.dapps_addresses(app.clone()).unwrap(), vec![1.into(), 2.into()]); assert_eq!(ap.dapps_addresses(app.clone()).unwrap(), vec![1.into(), 2.into()]);
} }
#[test]
fn should_set_dapps_policy() {
// given
let ap = AccountProvider::transient_provider();
let address = ap.new_account("test").unwrap();
// When returning nothing
ap.set_new_dapps_whitelist(Some(vec![])).unwrap();
assert_eq!(ap.dapps_addresses("app1".into()).unwrap(), vec![]);
// change to all
ap.set_new_dapps_whitelist(None).unwrap();
assert_eq!(ap.dapps_addresses("app1".into()).unwrap(), vec![address]);
// change to a whitelist
ap.set_new_dapps_whitelist(Some(vec![1.into()])).unwrap();
assert_eq!(ap.dapps_addresses("app1".into()).unwrap(), vec![1.into()]);
}
} }

View File

@ -17,11 +17,11 @@
//! Address Book and Dapps Settings Store //! Address Book and Dapps Settings Store
use std::{fs, fmt, hash, ops}; use std::{fs, fmt, hash, ops};
use std::collections::HashMap; use std::collections::{HashMap, VecDeque};
use std::path::PathBuf; use std::path::PathBuf;
use ethstore::ethkey::Address; use ethstore::ethkey::Address;
use ethjson::misc::{AccountMeta, DappsSettings as JsonSettings}; use ethjson::misc::{AccountMeta, DappsSettings as JsonSettings, NewDappsPolicy as JsonNewDappsPolicy};
use account_provider::DappId; use account_provider::DappId;
/// Disk-backed map from Address to String. Uses JSON. /// Disk-backed map from Address to String. Uses JSON.
@ -105,43 +105,106 @@ impl From<DappsSettings> for JsonSettings {
} }
} }
/// Dapps user settings
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum NewDappsPolicy {
AllAccounts,
Whitelist(Vec<Address>),
}
impl From<JsonNewDappsPolicy> for NewDappsPolicy {
fn from(s: JsonNewDappsPolicy) -> Self {
match s {
JsonNewDappsPolicy::AllAccounts => NewDappsPolicy::AllAccounts,
JsonNewDappsPolicy::Whitelist(accounts) => NewDappsPolicy::Whitelist(
accounts.into_iter().map(Into::into).collect()
),
}
}
}
impl From<NewDappsPolicy> for JsonNewDappsPolicy {
fn from(s: NewDappsPolicy) -> Self {
match s {
NewDappsPolicy::AllAccounts => JsonNewDappsPolicy::AllAccounts,
NewDappsPolicy::Whitelist(accounts) => JsonNewDappsPolicy::Whitelist(
accounts.into_iter().map(Into::into).collect()
),
}
}
}
const MAX_RECENT_DAPPS: usize = 10;
/// Disk-backed map from DappId to Settings. Uses JSON. /// Disk-backed map from DappId to Settings. Uses JSON.
pub struct DappsSettingsStore { pub struct DappsSettingsStore {
cache: DiskMap<DappId, DappsSettings>, /// Dapps Settings
settings: DiskMap<DappId, DappsSettings>,
/// New Dapps Policy
policy: DiskMap<String, NewDappsPolicy>,
/// Recently Accessed Dapps (transient)
recent: VecDeque<DappId>,
} }
impl DappsSettingsStore { impl DappsSettingsStore {
/// Creates new store at given directory path. /// Creates new store at given directory path.
pub fn new(path: String) -> Self { pub fn new(path: String) -> Self {
let mut r = DappsSettingsStore { let mut r = DappsSettingsStore {
cache: DiskMap::new(path, "dapps_accounts.json".into()) settings: DiskMap::new(path.clone(), "dapps_accounts.json".into()),
policy: DiskMap::new(path.clone(), "dapps_policy.json".into()),
recent: VecDeque::with_capacity(MAX_RECENT_DAPPS),
}; };
r.cache.revert(JsonSettings::read_dapps_settings); r.settings.revert(JsonSettings::read_dapps_settings);
r.policy.revert(JsonNewDappsPolicy::read_new_dapps_policy);
r r
} }
/// Creates transient store (no changes are saved to disk). /// Creates transient store (no changes are saved to disk).
pub fn transient() -> Self { pub fn transient() -> Self {
DappsSettingsStore { DappsSettingsStore {
cache: DiskMap::transient() settings: DiskMap::transient(),
policy: DiskMap::transient(),
recent: VecDeque::with_capacity(MAX_RECENT_DAPPS),
} }
} }
/// Get copy of the dapps settings /// Get copy of the dapps settings
pub fn get(&self) -> HashMap<DappId, DappsSettings> { pub fn settings(&self) -> HashMap<DappId, DappsSettings> {
self.cache.clone() self.settings.clone()
} }
fn save(&self) { /// Returns current new dapps policy
self.cache.save(JsonSettings::write_dapps_settings) pub fn policy(&self) -> NewDappsPolicy {
self.policy.get("default").cloned().unwrap_or(NewDappsPolicy::AllAccounts)
} }
/// Returns recent dapps (in order of last request)
pub fn recent_dapps(&self) -> Vec<DappId> {
self.recent.iter().cloned().collect()
}
/// Marks recent dapp as used
pub fn mark_dapp_used(&mut self, dapp: DappId) {
self.recent.retain(|id| id != &dapp);
self.recent.push_front(dapp);
while self.recent.len() > MAX_RECENT_DAPPS {
self.recent.pop_back();
}
}
/// Sets current new dapps policy
pub fn set_policy(&mut self, policy: NewDappsPolicy) {
self.policy.insert("default".into(), policy);
self.policy.save(JsonNewDappsPolicy::write_new_dapps_policy);
}
/// Sets accounts for specific dapp.
pub fn set_accounts(&mut self, id: DappId, accounts: Vec<Address>) { pub fn set_accounts(&mut self, id: DappId, accounts: Vec<Address>) {
{ {
let mut settings = self.cache.entry(id).or_insert_with(DappsSettings::default); let mut settings = self.settings.entry(id).or_insert_with(DappsSettings::default);
settings.accounts = accounts; settings.accounts = accounts;
} }
self.save(); self.settings.save(JsonSettings::write_dapps_settings);
} }
} }
@ -216,7 +279,7 @@ impl<K: hash::Hash + Eq, V> DiskMap<K, V> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{AddressBook, DappsSettingsStore, DappsSettings}; use super::{AddressBook, DappsSettingsStore, DappsSettings, NewDappsPolicy};
use std::collections::HashMap; use std::collections::HashMap;
use ethjson::misc::AccountMeta; use ethjson::misc::AccountMeta;
use devtools::RandomTempPath; use devtools::RandomTempPath;
@ -232,25 +295,6 @@ mod tests {
assert_eq!(b.get(), hash_map![1.into() => AccountMeta{name: "One".to_owned(), meta: "{1:1}".to_owned(), uuid: None}]); assert_eq!(b.get(), hash_map![1.into() => AccountMeta{name: "One".to_owned(), meta: "{1:1}".to_owned(), uuid: None}]);
} }
#[test]
fn should_save_and_reload_dapps_settings() {
// given
let temp = RandomTempPath::create_dir();
let path = temp.as_str().to_owned();
let mut b = DappsSettingsStore::new(path.clone());
// when
b.set_accounts("dappOne".into(), vec![1.into(), 2.into()]);
// then
let b = DappsSettingsStore::new(path);
assert_eq!(b.get(), hash_map![
"dappOne".into() => DappsSettings {
accounts: vec![1.into(), 2.into()],
}
]);
}
#[test] #[test]
fn should_remove_address() { fn should_remove_address() {
let temp = RandomTempPath::create_dir(); let temp = RandomTempPath::create_dir();
@ -268,4 +312,58 @@ mod tests {
3.into() => AccountMeta{name: "Three".to_owned(), meta: "{}".to_owned(), uuid: None} 3.into() => AccountMeta{name: "Three".to_owned(), meta: "{}".to_owned(), uuid: None}
]); ]);
} }
#[test]
fn should_save_and_reload_dapps_settings() {
// given
let temp = RandomTempPath::create_dir();
let path = temp.as_str().to_owned();
let mut b = DappsSettingsStore::new(path.clone());
// when
b.set_accounts("dappOne".into(), vec![1.into(), 2.into()]);
// then
let b = DappsSettingsStore::new(path);
assert_eq!(b.settings(), hash_map![
"dappOne".into() => DappsSettings {
accounts: vec![1.into(), 2.into()],
}
]);
}
#[test]
fn should_maintain_a_list_of_recent_dapps() {
let mut store = DappsSettingsStore::transient();
assert!(store.recent_dapps().is_empty(), "Initially recent dapps should be empty.");
store.mark_dapp_used("dapp1".into());
assert_eq!(store.recent_dapps(), vec!["dapp1".to_owned()]);
store.mark_dapp_used("dapp2".into());
assert_eq!(store.recent_dapps(), vec!["dapp2".to_owned(), "dapp1".to_owned()]);
store.mark_dapp_used("dapp1".into());
assert_eq!(store.recent_dapps(), vec!["dapp1".to_owned(), "dapp2".to_owned()]);
}
#[test]
fn should_store_dapps_policy() {
// given
let temp = RandomTempPath::create_dir();
let path = temp.as_str().to_owned();
let mut store = DappsSettingsStore::new(path.clone());
// Test default policy
assert_eq!(store.policy(), NewDappsPolicy::AllAccounts);
// when
store.set_policy(NewDappsPolicy::Whitelist(vec![1.into(), 2.into()]));
// then
let store = DappsSettingsStore::new(path);
assert_eq!(store.policy.clone(), hash_map![
"default".into() => NewDappsPolicy::Whitelist(vec![1.into(), 2.into()])
]);
}
} }

View File

@ -13,7 +13,9 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::collections::{HashSet, HashMap, BTreeMap, VecDeque}; use std::collections::{HashSet, HashMap, BTreeMap, VecDeque};
use std::str::FromStr;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use std::path::{Path}; use std::path::{Path};
use std::fmt; use std::fmt;
@ -22,7 +24,7 @@ use std::time::{Instant};
use time::precise_time_ns; use time::precise_time_ns;
// util // util
use util::{Bytes, PerfTimer, Itertools, Mutex, RwLock, Hashable}; use util::{Bytes, PerfTimer, Itertools, Mutex, RwLock, MutexGuard, Hashable};
use util::{journaldb, TrieFactory, Trie}; use util::{journaldb, TrieFactory, Trie};
use util::{U256, H256, Address, H2048, Uint, FixedHash}; use util::{U256, H256, Address, H2048, Uint, FixedHash};
use util::trie::TrieSpec; use util::trie::TrieSpec;
@ -42,7 +44,7 @@ use env_info::LastHashes;
use verification; use verification;
use verification::{PreverifiedBlock, Verifier}; use verification::{PreverifiedBlock, Verifier};
use block::*; use block::*;
use transaction::{LocalizedTransaction, SignedTransaction, Action}; use transaction::{LocalizedTransaction, SignedTransaction, Transaction, PendingTransaction, Action};
use blockchain::extras::TransactionAddress; use blockchain::extras::TransactionAddress;
use types::filter::Filter; use types::filter::Filter;
use types::mode::Mode as IpcMode; use types::mode::Mode as IpcMode;
@ -68,6 +70,7 @@ use factory::Factories;
use rlp::{decode, View, UntrustedRlp}; use rlp::{decode, View, UntrustedRlp};
use state_db::StateDB; use state_db::StateDB;
use rand::OsRng; use rand::OsRng;
use client::registry::Registry;
// re-export // re-export
pub use types::blockchain_info::BlockChainInfo; pub use types::blockchain_info::BlockChainInfo;
@ -124,6 +127,7 @@ impl SleepState {
/// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue. /// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue.
/// Call `import_block()` to import a block asynchronously; `flush_queue()` flushes the queue. /// Call `import_block()` to import a block asynchronously; `flush_queue()` flushes the queue.
pub struct Client { pub struct Client {
enabled: AtomicBool,
mode: Mutex<Mode>, mode: Mutex<Mode>,
chain: RwLock<Arc<BlockChain>>, chain: RwLock<Arc<BlockChain>>,
tracedb: RwLock<TraceDB<BlockChain>>, tracedb: RwLock<TraceDB<BlockChain>>,
@ -148,6 +152,7 @@ pub struct Client {
history: u64, history: u64,
rng: Mutex<OsRng>, rng: Mutex<OsRng>,
on_mode_change: Mutex<Option<Box<FnMut(&Mode) + 'static + Send>>>, on_mode_change: Mutex<Option<Box<FnMut(&Mode) + 'static + Send>>>,
registrar: Mutex<Option<Registry>>,
} }
impl Client { impl Client {
@ -160,6 +165,7 @@ impl Client {
message_channel: IoChannel<ClientIoMessage>, message_channel: IoChannel<ClientIoMessage>,
db_config: &DatabaseConfig, db_config: &DatabaseConfig,
) -> Result<Arc<Client>, ClientError> { ) -> Result<Arc<Client>, ClientError> {
let path = path.to_path_buf(); let path = path.to_path_buf();
let gb = spec.genesis_block(); let gb = spec.genesis_block();
@ -221,7 +227,8 @@ impl Client {
accountdb: Default::default(), accountdb: Default::default(),
}; };
let client = Client { let client = Arc::new(Client {
enabled: AtomicBool::new(true),
sleep_state: Mutex::new(SleepState::new(awake)), sleep_state: Mutex::new(SleepState::new(awake)),
liveness: AtomicBool::new(awake), liveness: AtomicBool::new(awake),
mode: Mutex::new(config.mode.clone()), mode: Mutex::new(config.mode.clone()),
@ -246,8 +253,15 @@ impl Client {
history: history, history: history,
rng: Mutex::new(try!(OsRng::new().map_err(::util::UtilError::StdIo))), rng: Mutex::new(try!(OsRng::new().map_err(::util::UtilError::StdIo))),
on_mode_change: Mutex::new(None), on_mode_change: Mutex::new(None),
}; registrar: Mutex::new(None),
Ok(Arc::new(client)) });
if let Some(reg_addr) = client.additional_params().get("registrar").and_then(|s| Address::from_str(s).ok()) {
trace!(target: "client", "Found registrar at {}", reg_addr);
let weak = Arc::downgrade(&client);
let registrar = Registry::new(reg_addr, move |a, d| weak.upgrade().ok_or("No client!".into()).and_then(|c| c.call_contract(a, d)));
*client.registrar.lock() = Some(registrar);
}
Ok(client)
} }
/// Adds an actor to be notified on certain events /// Adds an actor to be notified on certain events
@ -268,6 +282,11 @@ impl Client {
} }
} }
/// Get the Registry object - useful for looking up names.
pub fn registrar(&self) -> MutexGuard<Option<Registry>> {
self.registrar.lock()
}
/// Register an action to be done if a mode change happens. /// Register an action to be done if a mode change happens.
pub fn on_mode_change<F>(&self, f: F) where F: 'static + FnMut(&Mode) + Send { pub fn on_mode_change<F>(&self, f: F) where F: 'static + FnMut(&Mode) + Send {
*self.on_mode_change.lock() = Some(Box::new(f)); *self.on_mode_change.lock() = Some(Box::new(f));
@ -395,6 +414,12 @@ impl Client {
/// This is triggered by a message coming from a block queue when the block is ready for insertion /// This is triggered by a message coming from a block queue when the block is ready for insertion
pub fn import_verified_blocks(&self) -> usize { pub fn import_verified_blocks(&self) -> usize {
// Shortcut out if we know we're incapable of syncing the chain.
if !self.enabled.load(AtomicOrdering::Relaxed) {
return 0;
}
let max_blocks_to_import = 4; let max_blocks_to_import = 4;
let (imported_blocks, import_results, invalid_blocks, imported, proposed_blocks, duration, is_empty) = { let (imported_blocks, import_results, invalid_blocks, imported, proposed_blocks, duration, is_empty) = {
let mut imported_blocks = Vec::with_capacity(max_blocks_to_import); let mut imported_blocks = Vec::with_capacity(max_blocks_to_import);
@ -663,10 +688,17 @@ impl Client {
/// Tick the client. /// Tick the client.
// TODO: manage by real events. // TODO: manage by real events.
pub fn tick(&self) { pub fn tick(&self) {
self.check_garbage();
self.check_snooze();
}
fn check_garbage(&self) {
self.chain.read().collect_garbage(); self.chain.read().collect_garbage();
self.block_queue.collect_garbage(); self.block_queue.collect_garbage();
self.tracedb.read().collect_garbage(); self.tracedb.read().collect_garbage();
}
fn check_snooze(&self) {
let mode = self.mode.lock().clone(); let mode = self.mode.lock().clone();
match mode { match mode {
Mode::Dark(timeout) => { Mode::Dark(timeout) => {
@ -700,16 +732,6 @@ impl Client {
} }
} }
/// Look up the block number for the given block ID.
pub fn block_number(&self, id: BlockId) -> Option<BlockNumber> {
match id {
BlockId::Number(number) => Some(number),
BlockId::Hash(ref hash) => self.chain.read().block_number(hash),
BlockId::Earliest => Some(0),
BlockId::Latest | BlockId::Pending => Some(self.chain.read().best_block_number()),
}
}
/// Take a snapshot at the given block. /// Take a snapshot at the given block.
/// If the ID given is "latest", this will default to 1000 blocks behind. /// If the ID given is "latest", this will default to 1000 blocks behind.
pub fn take_snapshot<W: snapshot_io::SnapshotWriter + Send>(&self, writer: W, at: BlockId, p: &snapshot::Progress) -> Result<(), EthcoreError> { pub fn take_snapshot<W: snapshot_io::SnapshotWriter + Send>(&self, writer: W, at: BlockId, p: &snapshot::Progress) -> Result<(), EthcoreError> {
@ -908,8 +930,17 @@ impl BlockChainClient for Client {
r r
} }
fn disable(&self) {
self.set_mode(IpcMode::Off);
self.enabled.store(false, AtomicOrdering::Relaxed);
self.clear_queue();
}
fn set_mode(&self, new_mode: IpcMode) { fn set_mode(&self, new_mode: IpcMode) {
trace!(target: "mode", "Client::set_mode({:?})", new_mode); trace!(target: "mode", "Client::set_mode({:?})", new_mode);
if !self.enabled.load(AtomicOrdering::Relaxed) {
return;
}
{ {
let mut mode = self.mode.lock(); let mut mode = self.mode.lock();
*mode = new_mode.clone().into(); *mode = new_mode.clone().into();
@ -935,6 +966,15 @@ impl BlockChainClient for Client {
Self::block_hash(&chain, id).and_then(|hash| chain.block_header_data(&hash)) Self::block_hash(&chain, id).and_then(|hash| chain.block_header_data(&hash))
} }
fn block_number(&self, id: BlockId) -> Option<BlockNumber> {
match id {
BlockId::Number(number) => Some(number),
BlockId::Hash(ref hash) => self.chain.read().block_number(hash),
BlockId::Earliest => Some(0),
BlockId::Latest | BlockId::Pending => Some(self.chain.read().best_block_number()),
}
}
fn block_body(&self, id: BlockId) -> Option<Bytes> { fn block_body(&self, id: BlockId) -> Option<Bytes> {
let chain = self.chain.read(); let chain = self.chain.read();
Self::block_hash(&chain, id).and_then(|hash| chain.block_body(&hash)) Self::block_hash(&chain, id).and_then(|hash| chain.block_body(&hash))
@ -1294,8 +1334,8 @@ impl BlockChainClient for Client {
} }
} }
fn pending_transactions(&self) -> Vec<SignedTransaction> { fn ready_transactions(&self) -> Vec<PendingTransaction> {
self.miner.pending_transactions(self.chain.read().best_block_number()) self.miner.ready_transactions(self.chain.read().best_block_number())
} }
fn queue_consensus_message(&self, message: Bytes) { fn queue_consensus_message(&self, message: Bytes) {
@ -1331,6 +1371,34 @@ impl BlockChainClient for Client {
earliest_state: self.state_db.lock().journal_db().earliest_era().unwrap_or(0), earliest_state: self.state_db.lock().journal_db().earliest_era().unwrap_or(0),
} }
} }
fn call_contract(&self, address: Address, data: Bytes) -> Result<Bytes, String> {
let from = Address::default();
let transaction = Transaction {
nonce: self.latest_nonce(&from),
action: Action::Call(address),
gas: U256::from(50_000_000),
gas_price: U256::default(),
value: U256::default(),
data: data,
}.fake_sign(from);
self.call(&transaction, BlockId::Latest, Default::default())
.map_err(|e| format!("{:?}", e))
.map(|executed| {
executed.output
})
}
fn registrar_address(&self) -> Option<Address> {
self.registrar.lock().as_ref().map(|r| r.address.clone())
}
fn registry_address(&self, name: String) -> Option<Address> {
self.registrar.lock().as_ref()
.and_then(|r| r.get_address(&(name.as_bytes().sha3()), "A").ok())
.and_then(|a| if a.is_zero() { None } else { Some(a) })
}
} }
impl MiningBlockChainClient for Client { impl MiningBlockChainClient for Client {

View File

@ -1,3 +1,19 @@
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use trace::Error as TraceError; use trace::Error as TraceError;
use util::UtilError; use util::UtilError;
use std::fmt::{Display, Formatter, Error as FmtError}; use std::fmt::{Display, Formatter, Error as FmtError};

View File

@ -16,6 +16,7 @@
//! Blockchain database client. //! Blockchain database client.
mod registry;
mod config; mod config;
mod error; mod error;
mod test_client; mod test_client;

File diff suppressed because one or more lines are too long

View File

@ -21,7 +21,7 @@ use util::*;
use rlp::*; use rlp::*;
use ethkey::{Generator, Random}; use ethkey::{Generator, Random};
use devtools::*; use devtools::*;
use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action}; use transaction::{Transaction, LocalizedTransaction, SignedTransaction, PendingTransaction, Action};
use blockchain::TreeRoute; use blockchain::TreeRoute;
use client::{ use client::{
BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockId, BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockId,
@ -90,6 +90,8 @@ pub struct TestBlockChainClient {
pub ancient_block: RwLock<Option<(H256, u64)>>, pub ancient_block: RwLock<Option<(H256, u64)>>,
/// First block info. /// First block info.
pub first_block: RwLock<Option<(H256, u64)>>, pub first_block: RwLock<Option<(H256, u64)>>,
/// Traces to return
pub traces: RwLock<Option<Vec<LocalizedTrace>>>,
} }
/// Used for generating test client blocks. /// Used for generating test client blocks.
@ -151,6 +153,7 @@ impl TestBlockChainClient {
latest_block_timestamp: RwLock::new(10_000_000), latest_block_timestamp: RwLock::new(10_000_000),
ancient_block: RwLock::new(None), ancient_block: RwLock::new(None),
first_block: RwLock::new(None), first_block: RwLock::new(None),
traces: RwLock::new(None),
}; };
client.add_blocks(1, EachBlockWith::Nothing); // add genesis block client.add_blocks(1, EachBlockWith::Nothing); // add genesis block
client.genesis_hash = client.last_hash.read().clone(); client.genesis_hash = client.last_hash.read().clone();
@ -485,6 +488,10 @@ impl BlockChainClient for TestBlockChainClient {
self.block_hash(id).and_then(|hash| self.blocks.read().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec())) self.block_hash(id).and_then(|hash| self.blocks.read().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec()))
} }
fn block_number(&self, _id: BlockId) -> Option<BlockNumber> {
unimplemented!()
}
fn block_body(&self, id: BlockId) -> Option<Bytes> { fn block_body(&self, id: BlockId) -> Option<Bytes> {
self.block_hash(id).and_then(|hash| self.blocks.read().get(&hash).map(|r| { self.block_hash(id).and_then(|hash| self.blocks.read().get(&hash).map(|r| {
let mut stream = RlpStream::new_list(2); let mut stream = RlpStream::new_list(2);
@ -654,19 +661,19 @@ impl BlockChainClient for TestBlockChainClient {
} }
fn filter_traces(&self, _filter: TraceFilter) -> Option<Vec<LocalizedTrace>> { fn filter_traces(&self, _filter: TraceFilter) -> Option<Vec<LocalizedTrace>> {
unimplemented!(); self.traces.read().clone()
} }
fn trace(&self, _trace: TraceId) -> Option<LocalizedTrace> { fn trace(&self, _trace: TraceId) -> Option<LocalizedTrace> {
unimplemented!(); self.traces.read().clone().and_then(|vec| vec.into_iter().next())
} }
fn transaction_traces(&self, _trace: TransactionId) -> Option<Vec<LocalizedTrace>> { fn transaction_traces(&self, _trace: TransactionId) -> Option<Vec<LocalizedTrace>> {
unimplemented!(); self.traces.read().clone()
} }
fn block_traces(&self, _trace: BlockId) -> Option<Vec<LocalizedTrace>> { fn block_traces(&self, _trace: BlockId) -> Option<Vec<LocalizedTrace>> {
unimplemented!(); self.traces.read().clone()
} }
fn queue_transactions(&self, transactions: Vec<Bytes>, _peer_id: usize) { fn queue_transactions(&self, transactions: Vec<Bytes>, _peer_id: usize) {
@ -681,8 +688,8 @@ impl BlockChainClient for TestBlockChainClient {
fn broadcast_consensus_message(&self, _message: Bytes) {} fn broadcast_consensus_message(&self, _message: Bytes) {}
fn pending_transactions(&self) -> Vec<SignedTransaction> { fn ready_transactions(&self) -> Vec<PendingTransaction> {
self.miner.pending_transactions(self.chain_info().best_block_number) self.miner.ready_transactions(self.chain_info().best_block_number)
} }
fn signing_network_id(&self) -> Option<u64> { None } fn signing_network_id(&self) -> Option<u64> { None }
@ -691,10 +698,18 @@ impl BlockChainClient for TestBlockChainClient {
fn set_mode(&self, _: Mode) { unimplemented!(); } fn set_mode(&self, _: Mode) { unimplemented!(); }
fn disable(&self) { unimplemented!(); }
fn pruning_info(&self) -> PruningInfo { fn pruning_info(&self) -> PruningInfo {
PruningInfo { PruningInfo {
earliest_chain: 1, earliest_chain: 1,
earliest_state: 1, earliest_state: 1,
} }
} }
fn call_contract(&self, _address: Address, _data: Bytes) -> Result<Bytes, String> { Ok(vec![]) }
fn registrar_address(&self) -> Option<Address> { None }
fn registry_address(&self, _name: String) -> Option<Address> { None }
} }

View File

@ -21,7 +21,7 @@ use blockchain::TreeRoute;
use verification::queue::QueueInfo as BlockQueueInfo; use verification::queue::QueueInfo as BlockQueueInfo;
use block::{OpenBlock, SealedBlock}; use block::{OpenBlock, SealedBlock};
use header::{BlockNumber}; use header::{BlockNumber};
use transaction::{LocalizedTransaction, SignedTransaction}; use transaction::{LocalizedTransaction, SignedTransaction, PendingTransaction};
use log_entry::LocalizedLogEntry; use log_entry::LocalizedLogEntry;
use filter::Filter; use filter::Filter;
use views::{BlockView}; use views::{BlockView};
@ -52,6 +52,9 @@ pub trait BlockChainClient : Sync + Send {
/// Get raw block header data by block id. /// Get raw block header data by block id.
fn block_header(&self, id: BlockId) -> Option<Bytes>; fn block_header(&self, id: BlockId) -> Option<Bytes>;
/// Look up the block number for the given block ID.
fn block_number(&self, id: BlockId) -> Option<BlockNumber>;
/// Get raw block body data by block id. /// Get raw block body data by block id.
/// Block body is an RLP list of two items: uncles and transactions. /// Block body is an RLP list of two items: uncles and transactions.
fn block_body(&self, id: BlockId) -> Option<Bytes>; fn block_body(&self, id: BlockId) -> Option<Bytes>;
@ -208,8 +211,8 @@ pub trait BlockChainClient : Sync + Send {
/// Used by PoA to communicate with peers. /// Used by PoA to communicate with peers.
fn broadcast_consensus_message(&self, message: Bytes); fn broadcast_consensus_message(&self, message: Bytes);
/// list all transactions /// List all transactions that are allowed into the next block.
fn pending_transactions(&self) -> Vec<SignedTransaction>; fn ready_transactions(&self) -> Vec<PendingTransaction>;
/// Sorted list of transaction gas prices from at least last sample_size blocks. /// Sorted list of transaction gas prices from at least last sample_size blocks.
fn gas_price_corpus(&self, sample_size: usize) -> Vec<U256> { fn gas_price_corpus(&self, sample_size: usize) -> Vec<U256> {
@ -255,6 +258,10 @@ pub trait BlockChainClient : Sync + Send {
/// Set the mode. /// Set the mode.
fn set_mode(&self, mode: Mode); fn set_mode(&self, mode: Mode);
/// Disable the client from importing blocks. This cannot be undone in this session and indicates
/// that a subsystem has reason to believe this executable incapable of syncing the chain.
fn disable(&self);
/// Returns engine-related extra info for `BlockId`. /// Returns engine-related extra info for `BlockId`.
fn block_extra_info(&self, id: BlockId) -> Option<BTreeMap<String, String>>; fn block_extra_info(&self, id: BlockId) -> Option<BTreeMap<String, String>>;
@ -263,6 +270,15 @@ pub trait BlockChainClient : Sync + Send {
/// Returns information about pruning/data availability. /// Returns information about pruning/data availability.
fn pruning_info(&self) -> PruningInfo; fn pruning_info(&self) -> PruningInfo;
/// Like `call`, but with various defaults. Designed to be used for calling contracts.
fn call_contract(&self, address: Address, data: Bytes) -> Result<Bytes, String>;
/// Get the address of the registry itself.
fn registrar_address(&self) -> Option<Address>;
/// Get the address of a particular blockchain service, if available.
fn registry_address(&self, name: String) -> Option<Address>;
} }
impl IpcConfig for BlockChainClient { } impl IpcConfig for BlockChainClient { }

View File

@ -100,6 +100,7 @@ impl AsMillis for Duration {
impl AuthorityRound { impl AuthorityRound {
/// Create a new instance of AuthorityRound engine. /// Create a new instance of AuthorityRound engine.
pub fn new(params: CommonParams, our_params: AuthorityRoundParams, builtins: BTreeMap<Address, Builtin>) -> Result<Arc<Self>, Error> { pub fn new(params: CommonParams, our_params: AuthorityRoundParams, builtins: BTreeMap<Address, Builtin>) -> Result<Arc<Self>, Error> {
let should_timeout = our_params.start_step.is_none();
let initial_step = our_params.start_step.unwrap_or_else(|| (unix_now().as_secs() / our_params.step_duration.as_secs())) as usize; let initial_step = our_params.start_step.unwrap_or_else(|| (unix_now().as_secs() / our_params.step_duration.as_secs())) as usize;
let engine = Arc::new( let engine = Arc::new(
AuthorityRound { AuthorityRound {
@ -113,18 +114,17 @@ impl AuthorityRound {
account_provider: Mutex::new(None), account_provider: Mutex::new(None),
password: RwLock::new(None), password: RwLock::new(None),
}); });
let handler = TransitionHandler { engine: Arc::downgrade(&engine) }; // Do not initialize timeouts for tests.
try!(engine.transition_service.register_handler(Arc::new(handler))); if should_timeout {
let handler = TransitionHandler { engine: Arc::downgrade(&engine) };
try!(engine.transition_service.register_handler(Arc::new(handler)));
}
Ok(engine) Ok(engine)
} }
fn step(&self) -> usize {
self.step.load(AtomicOrdering::SeqCst)
}
fn remaining_step_duration(&self) -> Duration { fn remaining_step_duration(&self) -> Duration {
let now = unix_now(); let now = unix_now();
let step_end = self.our_params.step_duration * (self.step() as u32 + 1); let step_end = self.our_params.step_duration * (self.step.load(AtomicOrdering::SeqCst) as u32 + 1);
if step_end > now { if step_end > now {
step_end - now step_end - now
} else { } else {
@ -228,7 +228,7 @@ impl Engine for AuthorityRound {
fn generate_seal(&self, block: &ExecutedBlock) -> Seal { fn generate_seal(&self, block: &ExecutedBlock) -> Seal {
if self.proposed.load(AtomicOrdering::SeqCst) { return Seal::None; } if self.proposed.load(AtomicOrdering::SeqCst) { return Seal::None; }
let header = block.header(); let header = block.header();
let step = self.step(); let step = self.step.load(AtomicOrdering::SeqCst);
if self.is_step_proposer(step, header.author()) { if self.is_step_proposer(step, header.author()) {
if let Some(ref ap) = *self.account_provider.lock() { if let Some(ref ap) = *self.account_provider.lock() {
// Account should be permanently unlocked, otherwise sealing will fail. // Account should be permanently unlocked, otherwise sealing will fail.
@ -265,7 +265,7 @@ impl Engine for AuthorityRound {
fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> { fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
let header_step = try!(header_step(header)); let header_step = try!(header_step(header));
// Give one step slack if step is lagging, double vote is still not possible. // Give one step slack if step is lagging, double vote is still not possible.
if header_step <= self.step() + 1 { if header_step <= self.step.load(AtomicOrdering::SeqCst) + 1 {
let proposer_signature = try!(header_signature(header)); let proposer_signature = try!(header_signature(header));
let ok_sig = try!(verify_address(self.step_proposer(header_step), &proposer_signature, &header.bare_hash())); let ok_sig = try!(verify_address(self.step_proposer(header_step), &proposer_signature, &header.bare_hash()));
if ok_sig { if ok_sig {

View File

@ -661,10 +661,10 @@ mod tests {
use block::*; use block::*;
use error::{Error, BlockError}; use error::{Error, BlockError};
use header::Header; use header::Header;
use io::IoChannel;
use env_info::EnvInfo; use env_info::EnvInfo;
use tests::helpers::*; use tests::helpers::*;
use account_provider::AccountProvider; use account_provider::AccountProvider;
use io::IoService;
use service::ClientIoMessage; use service::ClientIoMessage;
use spec::Spec; use spec::Spec;
use engines::{Engine, EngineError, Seal}; use engines::{Engine, EngineError, Seal};
@ -904,10 +904,9 @@ mod tests {
let proposal = Some(b.header().bare_hash()); let proposal = Some(b.header().bare_hash());
// Register IoHandler remembers messages. // Register IoHandler remembers messages.
let io_service = IoService::<ClientIoMessage>::start().unwrap();
let test_io = TestIo::new(); let test_io = TestIo::new();
io_service.register_handler(test_io.clone()).unwrap(); let channel = IoChannel::to_handler(Arc::downgrade(&(test_io.clone() as Arc<IoHandler<ClientIoMessage>>)));
engine.register_message_channel(io_service.channel()); engine.register_message_channel(channel);
let prevote_current = vote(&engine, |mh| tap.sign(v0, None, mh).map(H520::from), h, r, Step::Prevote, proposal); let prevote_current = vote(&engine, |mh| tap.sign(v0, None, mh).map(H520::from), h, r, Step::Prevote, proposal);
@ -915,9 +914,6 @@ mod tests {
let prevote_future = vote(&engine, |mh| tap.sign(v0, None, mh).map(H520::from), h + 1, r, Step::Prevote, proposal); let prevote_future = vote(&engine, |mh| tap.sign(v0, None, mh).map(H520::from), h + 1, r, Step::Prevote, proposal);
// Wait a bit for async stuff.
::std::thread::sleep(::std::time::Duration::from_millis(500));
// Relays all valid present and future messages. // Relays all valid present and future messages.
assert!(test_io.received.read().contains(&ClientIoMessage::BroadcastMessage(prevote_current))); assert!(test_io.received.read().contains(&ClientIoMessage::BroadcastMessage(prevote_current)));
assert!(test_io.received.read().contains(&ClientIoMessage::BroadcastMessage(precommit_current))); assert!(test_io.received.read().contains(&ClientIoMessage::BroadcastMessage(precommit_current)));
@ -941,9 +937,8 @@ mod tests {
// Register IoHandler remembers messages. // Register IoHandler remembers messages.
let test_io = TestIo::new(); let test_io = TestIo::new();
let io_service = IoService::<ClientIoMessage>::start().unwrap(); let channel = IoChannel::to_handler(Arc::downgrade(&(test_io.clone() as Arc<IoHandler<ClientIoMessage>>)));
io_service.register_handler(test_io.clone()).unwrap(); engine.register_message_channel(channel);
engine.register_message_channel(io_service.channel());
// Propose // Propose
let (b, mut seal) = propose_default(&spec, v1.clone()); let (b, mut seal) = propose_default(&spec, v1.clone());
@ -956,11 +951,12 @@ mod tests {
vote(&engine, |mh| tap.sign(v1, None, mh).map(H520::from), h, r, Step::Precommit, proposal); vote(&engine, |mh| tap.sign(v1, None, mh).map(H520::from), h, r, Step::Precommit, proposal);
vote(&engine, |mh| tap.sign(v0, None, mh).map(H520::from), h, r, Step::Precommit, proposal); vote(&engine, |mh| tap.sign(v0, None, mh).map(H520::from), h, r, Step::Precommit, proposal);
// Wait a bit for async stuff.
::std::thread::sleep(::std::time::Duration::from_millis(500));
seal[2] = precommit_signatures(&tap, h, r, Some(b.header().bare_hash()), v1, v0); seal[2] = precommit_signatures(&tap, h, r, Some(b.header().bare_hash()), v1, v0);
assert!(test_io.received.read().contains(&ClientIoMessage::SubmitSeal(proposal.unwrap(), seal))); let first = test_io.received.read().contains(&ClientIoMessage::SubmitSeal(proposal.unwrap(), seal.clone()));
seal[2] = precommit_signatures(&tap, h, r, Some(b.header().bare_hash()), v0, v1);
let second = test_io.received.read().contains(&ClientIoMessage::SubmitSeal(proposal.unwrap(), seal));
assert!(first ^ second);
engine.stop(); engine.stop();
} }
} }

View File

@ -178,15 +178,15 @@ impl Engine for Ethash {
let gas_limit = { let gas_limit = {
let gas_limit = parent.gas_limit().clone(); let gas_limit = parent.gas_limit().clone();
let bound_divisor = self.ethash_params.gas_limit_bound_divisor; let bound_divisor = self.ethash_params.gas_limit_bound_divisor;
let lower_limit = gas_limit - gas_limit / bound_divisor + 1.into();
let upper_limit = gas_limit + gas_limit / bound_divisor - 1.into();
if gas_limit < gas_floor_target { if gas_limit < gas_floor_target {
min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into()) min(gas_floor_target, upper_limit)
} else if gas_limit > gas_ceil_target { } else if gas_limit > gas_ceil_target {
max(gas_ceil_target, gas_limit - gas_limit / bound_divisor + 1.into()) max(gas_ceil_target, lower_limit)
} else { } else {
min(gas_ceil_target, max(gas_floor_target, min(min(gas_ceil_target, upper_limit),
max(gas_floor_target, lower_limit + (header.gas_used().clone() * 6.into() / 5.into()) / bound_divisor))
gas_limit - gas_limit / bound_divisor + 1.into() +
(header.gas_used().clone() * 6.into() / 5.into()) / bound_divisor))
} }
}; };
header.set_difficulty(difficulty); header.set_difficulty(difficulty);

View File

@ -29,6 +29,12 @@ pub use self::denominations::*;
use super::spec::*; use super::spec::*;
/// Most recent fork block that we support on Mainnet.
pub const FORK_SUPPORTED_FRONTIER: u64 = 2675000;
/// Most recent fork block that we support on Ropsten.
pub const FORK_SUPPORTED_ROPSTEN: u64 = 10;
fn load(b: &[u8]) -> Spec { fn load(b: &[u8]) -> Spec {
Spec::load(b).expect("chain spec is invalid") Spec::load(b).expect("chain spec is invalid")
} }

View File

@ -118,6 +118,7 @@ extern crate lru_cache;
#[cfg(feature = "jit" )] #[cfg(feature = "jit" )]
extern crate evmjit; extern crate evmjit;
extern crate ethabi;
pub extern crate ethstore; pub extern crate ethstore;

View File

@ -115,7 +115,7 @@ impl BanningTransactionQueue {
} }
} }
} }
self.queue.add(transaction, TransactionOrigin::External, account_details, gas_estimator) self.queue.add(transaction, TransactionOrigin::External, None, account_details, gas_estimator)
} }
/// Ban transaction with given hash. /// Ban transaction with given hash.
@ -263,7 +263,7 @@ mod tests {
let mut txq = queue(); let mut txq = queue();
// when // when
txq.queue().add(tx, TransactionOrigin::External, &default_account_details, &gas_required).unwrap(); txq.queue().add(tx, TransactionOrigin::External, None, &default_account_details, &gas_required).unwrap();
// then // then
// should also deref to queue // should also deref to queue

View File

@ -28,7 +28,7 @@ use client::TransactionImportResult;
use executive::contract_address; use executive::contract_address;
use block::{ClosedBlock, IsBlock, Block}; use block::{ClosedBlock, IsBlock, Block};
use error::*; use error::*;
use transaction::{Action, SignedTransaction}; use transaction::{Action, SignedTransaction, PendingTransaction};
use receipt::{Receipt, RichReceipt}; use receipt::{Receipt, RichReceipt};
use spec::Spec; use spec::Spec;
use engines::{Engine, Seal}; use engines::{Engine, Seal};
@ -320,11 +320,12 @@ impl Miner {
} }
let _timer = PerfTimer::new("prepare_block"); let _timer = PerfTimer::new("prepare_block");
let chain_info = chain.chain_info();
let (transactions, mut open_block, original_work_hash) = { let (transactions, mut open_block, original_work_hash) = {
let transactions = {self.transaction_queue.lock().top_transactions()}; let transactions = {self.transaction_queue.lock().top_transactions_at(chain_info.best_block_number)};
let mut sealing_work = self.sealing_work.lock(); let mut sealing_work = self.sealing_work.lock();
let last_work_hash = sealing_work.queue.peek_last_ref().map(|pb| pb.block().fields().header.hash()); let last_work_hash = sealing_work.queue.peek_last_ref().map(|pb| pb.block().fields().header.hash());
let best_hash = chain.best_block_header().sha3(); let best_hash = chain_info.best_block_hash;
/* /*
// check to see if last ClosedBlock in would_seals is actually same parent block. // check to see if last ClosedBlock in would_seals is actually same parent block.
// if so // if so
@ -577,8 +578,14 @@ impl Miner {
prepare_new prepare_new
} }
fn add_transactions_to_queue(&self, chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>, default_origin: TransactionOrigin, transaction_queue: &mut BanningTransactionQueue) -> fn add_transactions_to_queue(
Vec<Result<TransactionImportResult, Error>> { &self,
chain: &MiningBlockChainClient,
transactions: Vec<SignedTransaction>,
default_origin: TransactionOrigin,
min_block: Option<BlockNumber>,
transaction_queue: &mut BanningTransactionQueue)
-> Vec<Result<TransactionImportResult, Error>> {
let fetch_account = |a: &Address| AccountDetails { let fetch_account = |a: &Address| AccountDetails {
nonce: chain.latest_nonce(a), nonce: chain.latest_nonce(a),
@ -613,7 +620,7 @@ impl Miner {
match origin { match origin {
TransactionOrigin::Local | TransactionOrigin::RetractedBlock => { TransactionOrigin::Local | TransactionOrigin::RetractedBlock => {
transaction_queue.add(tx, origin, &fetch_account, &gas_required) transaction_queue.add(tx, origin, min_block, &fetch_account, &gas_required)
}, },
TransactionOrigin::External => { TransactionOrigin::External => {
transaction_queue.add_with_banlist(tx, &fetch_account, &gas_required) transaction_queue.add_with_banlist(tx, &fetch_account, &gas_required)
@ -839,7 +846,7 @@ impl MinerService for Miner {
let results = { let results = {
let mut transaction_queue = self.transaction_queue.lock(); let mut transaction_queue = self.transaction_queue.lock();
self.add_transactions_to_queue( self.add_transactions_to_queue(
chain, transactions, TransactionOrigin::External, &mut transaction_queue chain, transactions, TransactionOrigin::External, None, &mut transaction_queue
) )
}; };
@ -857,17 +864,17 @@ impl MinerService for Miner {
fn import_own_transaction( fn import_own_transaction(
&self, &self,
chain: &MiningBlockChainClient, chain: &MiningBlockChainClient,
transaction: SignedTransaction, pending: PendingTransaction,
) -> Result<TransactionImportResult, Error> { ) -> Result<TransactionImportResult, Error> {
let hash = transaction.hash(); let hash = pending.transaction.hash();
trace!(target: "own_tx", "Importing transaction: {:?}", transaction); trace!(target: "own_tx", "Importing transaction: {:?}", pending);
let imported = { let imported = {
// Be sure to release the lock before we call prepare_work_sealing // Be sure to release the lock before we call prepare_work_sealing
let mut transaction_queue = self.transaction_queue.lock(); let mut transaction_queue = self.transaction_queue.lock();
let import = self.add_transactions_to_queue( let import = self.add_transactions_to_queue(
chain, vec![transaction], TransactionOrigin::Local, &mut transaction_queue chain, vec![pending.transaction], TransactionOrigin::Local, pending.min_block, &mut transaction_queue
).pop().expect("one result returned per added transaction; one added => one result; qed"); ).pop().expect("one result returned per added transaction; one added => one result; qed");
match import { match import {
@ -902,9 +909,9 @@ impl MinerService for Miner {
imported imported
} }
fn all_transactions(&self) -> Vec<SignedTransaction> { fn pending_transactions(&self) -> Vec<PendingTransaction> {
let queue = self.transaction_queue.lock(); let queue = self.transaction_queue.lock();
queue.top_transactions() queue.pending_transactions(BlockNumber::max_value())
} }
fn local_transactions(&self) -> BTreeMap<H256, LocalTransactionStatus> { fn local_transactions(&self) -> BTreeMap<H256, LocalTransactionStatus> {
@ -915,22 +922,26 @@ impl MinerService for Miner {
.collect() .collect()
} }
fn pending_transactions(&self, best_block: BlockNumber) -> Vec<SignedTransaction> { fn future_transactions(&self) -> Vec<PendingTransaction> {
self.transaction_queue.lock().future_transactions()
}
fn ready_transactions(&self, best_block: BlockNumber) -> Vec<PendingTransaction> {
let queue = self.transaction_queue.lock(); let queue = self.transaction_queue.lock();
match self.options.pending_set { match self.options.pending_set {
PendingSet::AlwaysQueue => queue.top_transactions(), PendingSet::AlwaysQueue => queue.pending_transactions(best_block),
PendingSet::SealingOrElseQueue => { PendingSet::SealingOrElseQueue => {
self.from_pending_block( self.from_pending_block(
best_block, best_block,
|| queue.top_transactions(), || queue.pending_transactions(best_block),
|sealing| sealing.transactions().to_owned() |sealing| sealing.transactions().iter().map(|t| t.clone().into()).collect()
) )
}, },
PendingSet::AlwaysSealing => { PendingSet::AlwaysSealing => {
self.from_pending_block( self.from_pending_block(
best_block, best_block,
|| vec![], || vec![],
|sealing| sealing.transactions().to_owned() |sealing| sealing.transactions().iter().map(|t| t.clone().into()).collect()
) )
}, },
} }
@ -1126,7 +1137,7 @@ impl MinerService for Miner {
}).for_each(|txs| { }).for_each(|txs| {
let mut transaction_queue = self.transaction_queue.lock(); let mut transaction_queue = self.transaction_queue.lock();
let _ = self.add_transactions_to_queue( let _ = self.add_transactions_to_queue(
chain, txs, TransactionOrigin::RetractedBlock, &mut transaction_queue chain, txs, TransactionOrigin::RetractedBlock, None, &mut transaction_queue
); );
}); });
} }
@ -1159,7 +1170,7 @@ mod tests {
use ethkey::{Generator, Random}; use ethkey::{Generator, Random};
use client::{BlockChainClient, TestBlockChainClient, EachBlockWith, TransactionImportResult}; use client::{BlockChainClient, TestBlockChainClient, EachBlockWith, TransactionImportResult};
use header::BlockNumber; use header::BlockNumber;
use types::transaction::{Transaction, SignedTransaction, Action}; use types::transaction::{Transaction, SignedTransaction, PendingTransaction, Action};
use spec::Spec; use spec::Spec;
use tests::helpers::{generate_dummy_client}; use tests::helpers::{generate_dummy_client};
@ -1238,12 +1249,12 @@ mod tests {
let transaction = transaction(); let transaction = transaction();
let best_block = 0; let best_block = 0;
// when // when
let res = miner.import_own_transaction(&client, transaction); let res = miner.import_own_transaction(&client, PendingTransaction::new(transaction, None));
// then // then
assert_eq!(res.unwrap(), TransactionImportResult::Current); assert_eq!(res.unwrap(), TransactionImportResult::Current);
assert_eq!(miner.all_transactions().len(), 1); assert_eq!(miner.pending_transactions().len(), 1);
assert_eq!(miner.pending_transactions(best_block).len(), 1); assert_eq!(miner.ready_transactions(best_block).len(), 1);
assert_eq!(miner.pending_transactions_hashes(best_block).len(), 1); assert_eq!(miner.pending_transactions_hashes(best_block).len(), 1);
assert_eq!(miner.pending_receipts(best_block).len(), 1); assert_eq!(miner.pending_receipts(best_block).len(), 1);
// This method will let us know if pending block was created (before calling that method) // This method will let us know if pending block was created (before calling that method)
@ -1258,12 +1269,12 @@ mod tests {
let transaction = transaction(); let transaction = transaction();
let best_block = 10; let best_block = 10;
// when // when
let res = miner.import_own_transaction(&client, transaction); let res = miner.import_own_transaction(&client, PendingTransaction::new(transaction, None));
// then // then
assert_eq!(res.unwrap(), TransactionImportResult::Current); assert_eq!(res.unwrap(), TransactionImportResult::Current);
assert_eq!(miner.all_transactions().len(), 1); assert_eq!(miner.pending_transactions().len(), 1);
assert_eq!(miner.pending_transactions(best_block).len(), 0); assert_eq!(miner.ready_transactions(best_block).len(), 0);
assert_eq!(miner.pending_transactions_hashes(best_block).len(), 0); assert_eq!(miner.pending_transactions_hashes(best_block).len(), 0);
assert_eq!(miner.pending_receipts(best_block).len(), 0); assert_eq!(miner.pending_receipts(best_block).len(), 0);
} }
@ -1280,9 +1291,9 @@ mod tests {
// then // then
assert_eq!(res.unwrap(), TransactionImportResult::Current); assert_eq!(res.unwrap(), TransactionImportResult::Current);
assert_eq!(miner.all_transactions().len(), 1); assert_eq!(miner.pending_transactions().len(), 1);
assert_eq!(miner.pending_transactions_hashes(best_block).len(), 0); assert_eq!(miner.pending_transactions_hashes(best_block).len(), 0);
assert_eq!(miner.pending_transactions(best_block).len(), 0); assert_eq!(miner.ready_transactions(best_block).len(), 0);
assert_eq!(miner.pending_receipts(best_block).len(), 0); assert_eq!(miner.pending_receipts(best_block).len(), 0);
// This method will let us know if pending block was created (before calling that method) // This method will let us know if pending block was created (before calling that method)
assert!(miner.prepare_work_sealing(&client)); assert!(miner.prepare_work_sealing(&client));
@ -1315,7 +1326,7 @@ mod tests {
assert!(miner.pending_block().is_none()); assert!(miner.pending_block().is_none());
assert_eq!(client.chain_info().best_block_number, 3 as BlockNumber); assert_eq!(client.chain_info().best_block_number, 3 as BlockNumber);
assert_eq!(miner.import_own_transaction(client, transaction()).unwrap(), TransactionImportResult::Current); assert_eq!(miner.import_own_transaction(client, PendingTransaction::new(transaction(), None)).unwrap(), TransactionImportResult::Current);
miner.update_sealing(client); miner.update_sealing(client);
client.flush_queue(); client.flush_queue();

View File

@ -62,7 +62,7 @@ use block::ClosedBlock;
use header::BlockNumber; use header::BlockNumber;
use receipt::{RichReceipt, Receipt}; use receipt::{RichReceipt, Receipt};
use error::{Error, CallError}; use error::{Error, CallError};
use transaction::SignedTransaction; use transaction::{SignedTransaction, PendingTransaction};
/// Miner client API /// Miner client API
pub trait MinerService : Send + Sync { pub trait MinerService : Send + Sync {
@ -118,7 +118,7 @@ pub trait MinerService : Send + Sync {
Vec<Result<TransactionImportResult, Error>>; Vec<Result<TransactionImportResult, Error>>;
/// Imports own (node owner) transaction to queue. /// Imports own (node owner) transaction to queue.
fn import_own_transaction(&self, chain: &MiningBlockChainClient, transaction: SignedTransaction) -> fn import_own_transaction(&self, chain: &MiningBlockChainClient, transaction: PendingTransaction) ->
Result<TransactionImportResult, Error>; Result<TransactionImportResult, Error>;
/// Returns hashes of transactions currently in pending /// Returns hashes of transactions currently in pending
@ -144,11 +144,14 @@ pub trait MinerService : Send + Sync {
/// Query pending transactions for hash. /// Query pending transactions for hash.
fn transaction(&self, best_block: BlockNumber, hash: &H256) -> Option<SignedTransaction>; fn transaction(&self, best_block: BlockNumber, hash: &H256) -> Option<SignedTransaction>;
/// Get a list of all transactions. /// Get a list of all pending transactions in the queue.
fn all_transactions(&self) -> Vec<SignedTransaction>; fn pending_transactions(&self) -> Vec<PendingTransaction>;
/// Get a list of all pending transactions. /// Get a list of all transactions that can go into the given block.
fn pending_transactions(&self, best_block: BlockNumber) -> Vec<SignedTransaction>; fn ready_transactions(&self, best_block: BlockNumber) -> Vec<PendingTransaction>;
/// Get a list of all future transactions.
fn future_transactions(&self) -> Vec<PendingTransaction>;
/// Get a list of local transactions with statuses. /// Get a list of local transactions with statuses.
fn local_transactions(&self) -> BTreeMap<H256, LocalTransactionStatus>; fn local_transactions(&self) -> BTreeMap<H256, LocalTransactionStatus>;

View File

@ -51,8 +51,8 @@
//! let gas_estimator = |_tx: &SignedTransaction| 2.into(); //! let gas_estimator = |_tx: &SignedTransaction| 2.into();
//! //!
//! let mut txq = TransactionQueue::default(); //! let mut txq = TransactionQueue::default();
//! txq.add(st2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); //! txq.add(st2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
//! txq.add(st1.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); //! txq.add(st1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
//! //!
//! // Check status //! // Check status
//! assert_eq!(txq.status().pending, 2); //! assert_eq!(txq.status().pending, 2);
@ -94,6 +94,7 @@ use util::table::Table;
use transaction::*; use transaction::*;
use error::{Error, TransactionError}; use error::{Error, TransactionError};
use client::TransactionImportResult; use client::TransactionImportResult;
use header::BlockNumber;
use miner::local_transactions::{LocalTransactionsList, Status as LocalTransactionStatus}; use miner::local_transactions::{LocalTransactionsList, Status as LocalTransactionStatus};
/// Transaction origin /// Transaction origin
@ -253,18 +254,21 @@ impl Ord for TransactionOrder {
/// Verified transaction (with sender) /// Verified transaction (with sender)
#[derive(Debug)] #[derive(Debug)]
struct VerifiedTransaction { struct VerifiedTransaction {
/// Transaction /// Transaction.
transaction: SignedTransaction, transaction: SignedTransaction,
/// transaction origin /// Transaction origin.
origin: TransactionOrigin, origin: TransactionOrigin,
/// Delay until specifid block.
min_block: Option<BlockNumber>,
} }
impl VerifiedTransaction { impl VerifiedTransaction {
fn new(transaction: SignedTransaction, origin: TransactionOrigin) -> Result<Self, Error> { fn new(transaction: SignedTransaction, origin: TransactionOrigin, min_block: Option<BlockNumber>) -> Result<Self, Error> {
try!(transaction.sender()); try!(transaction.sender());
Ok(VerifiedTransaction { Ok(VerifiedTransaction {
transaction: transaction, transaction: transaction,
origin: origin, origin: origin,
min_block: min_block,
}) })
} }
@ -620,6 +624,7 @@ impl TransactionQueue {
&mut self, &mut self,
tx: SignedTransaction, tx: SignedTransaction,
origin: TransactionOrigin, origin: TransactionOrigin,
min_block: Option<BlockNumber>,
fetch_account: &F, fetch_account: &F,
gas_estimator: &G, gas_estimator: &G,
) -> Result<TransactionImportResult, Error> where ) -> Result<TransactionImportResult, Error> where
@ -630,7 +635,7 @@ impl TransactionQueue {
let hash = tx.hash(); let hash = tx.hash();
let cloned_tx = tx.clone(); let cloned_tx = tx.clone();
let result = self.add_internal(tx, origin, fetch_account, gas_estimator); let result = self.add_internal(tx, origin, min_block, fetch_account, gas_estimator);
match result { match result {
Ok(TransactionImportResult::Current) => { Ok(TransactionImportResult::Current) => {
self.local_transactions.mark_pending(hash); self.local_transactions.mark_pending(hash);
@ -651,7 +656,7 @@ impl TransactionQueue {
} }
result result
} else { } else {
self.add_internal(tx, origin, fetch_account, gas_estimator) self.add_internal(tx, origin, min_block, fetch_account, gas_estimator)
} }
} }
@ -660,6 +665,7 @@ impl TransactionQueue {
&mut self, &mut self,
tx: SignedTransaction, tx: SignedTransaction,
origin: TransactionOrigin, origin: TransactionOrigin,
min_block: Option<BlockNumber>,
fetch_account: &F, fetch_account: &F,
gas_estimator: &G, gas_estimator: &G,
) -> Result<TransactionImportResult, Error> where ) -> Result<TransactionImportResult, Error> where
@ -728,7 +734,7 @@ impl TransactionQueue {
// Verify signature // Verify signature
try!(tx.check_low_s()); try!(tx.check_low_s());
let vtx = try!(VerifiedTransaction::new(tx, origin)); let vtx = try!(VerifiedTransaction::new(tx, origin, min_block));
let client_account = fetch_account(&vtx.sender()); let client_account = fetch_account(&vtx.sender());
let cost = vtx.transaction.value + vtx.transaction.gas_price * vtx.transaction.gas; let cost = vtx.transaction.value + vtx.transaction.gas_price * vtx.transaction.gas;
@ -968,10 +974,48 @@ impl TransactionQueue {
/// Returns top transactions from the queue ordered by priority. /// Returns top transactions from the queue ordered by priority.
pub fn top_transactions(&self) -> Vec<SignedTransaction> { pub fn top_transactions(&self) -> Vec<SignedTransaction> {
self.current.by_priority self.top_transactions_at(BlockNumber::max_value())
}
fn filter_pending_transaction<F>(&self, best_block: BlockNumber, mut f: F)
where F: FnMut(&VerifiedTransaction) {
let mut delayed = HashSet::new();
for t in self.current.by_priority.iter() {
let tx = self.by_hash.get(&t.hash).expect("All transactions in `current` and `future` are always included in `by_hash`");
let sender = tx.sender();
if delayed.contains(&sender) {
continue;
}
if tx.min_block.unwrap_or(0) > best_block {
delayed.insert(sender);
continue;
}
f(&tx);
}
}
/// Returns top transactions from the queue ordered by priority.
pub fn top_transactions_at(&self, best_block: BlockNumber) -> Vec<SignedTransaction> {
let mut r = Vec::new();
self.filter_pending_transaction(best_block, |tx| r.push(tx.transaction.clone()));
r
}
/// Return all ready transactions.
pub fn pending_transactions(&self, best_block: BlockNumber) -> Vec<PendingTransaction> {
let mut r = Vec::new();
self.filter_pending_transaction(best_block, |tx| r.push(PendingTransaction::new(tx.transaction.clone(), tx.min_block)));
r
}
/// Return all ready transactions.
pub fn future_transactions(&self) -> Vec<PendingTransaction> {
self.future.by_priority
.iter() .iter()
.map(|t| self.by_hash.get(&t.hash).expect("All transactions in `current` and `future` are always included in `by_hash`")) .map(|t| self.by_hash.get(&t.hash).expect("All transactions in `current` and `future` are always included in `by_hash`"))
.map(|t| t.transaction.clone()) .map(|t| PendingTransaction { transaction: t.transaction.clone(), min_block: t.min_block })
.collect() .collect()
} }
@ -980,15 +1024,6 @@ impl TransactionQueue {
self.local_transactions.all_transactions() self.local_transactions.all_transactions()
} }
#[cfg(test)]
fn future_transactions(&self) -> Vec<SignedTransaction> {
self.future.by_priority
.iter()
.map(|t| self.by_hash.get(&t.hash).expect("All transactions in `current` and `future` are always included in `by_hash`"))
.map(|t| t.transaction.clone())
.collect()
}
/// Returns hashes of all transactions from current, ordered by priority. /// Returns hashes of all transactions from current, ordered by priority.
pub fn pending_hashes(&self) -> Vec<H256> { pub fn pending_hashes(&self) -> Vec<H256> {
self.current.by_priority self.current.by_priority
@ -1353,14 +1388,14 @@ mod test {
let (tx1, tx2) = new_tx_pair(123.into(), 1.into(), 1.into(), 0.into()); let (tx1, tx2) = new_tx_pair(123.into(), 1.into(), 1.into(), 0.into());
let sender = tx1.sender().unwrap(); let sender = tx1.sender().unwrap();
let nonce = tx1.nonce; let nonce = tx1.nonce;
txq.add(tx1.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 2); assert_eq!(txq.status().pending, 2);
assert_eq!(txq.last_nonce(&sender), Some(nonce + 1.into())); assert_eq!(txq.last_nonce(&sender), Some(nonce + 1.into()));
// when // when
let tx = new_tx(123.into(), 1.into()); let tx = new_tx(123.into(), 1.into());
let res = txq.add(tx.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator); let res = txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator);
// then // then
// No longer the case as we don't even consider a transaction that isn't above a full // No longer the case as we don't even consider a transaction that isn't above a full
@ -1392,12 +1427,12 @@ mod test {
gas_limit: !U256::zero(), gas_limit: !U256::zero(),
}; };
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
let tx1 = VerifiedTransaction::new(tx1, TransactionOrigin::External).unwrap(); let tx1 = VerifiedTransaction::new(tx1, TransactionOrigin::External, None).unwrap();
let tx2 = VerifiedTransaction::new(tx2, TransactionOrigin::External).unwrap(); let tx2 = VerifiedTransaction::new(tx2, TransactionOrigin::External, None).unwrap();
let mut by_hash = { let mut by_hash = {
let mut x = HashMap::new(); let mut x = HashMap::new();
let tx1 = VerifiedTransaction::new(tx1.transaction.clone(), TransactionOrigin::External).unwrap(); let tx1 = VerifiedTransaction::new(tx1.transaction.clone(), TransactionOrigin::External, None).unwrap();
let tx2 = VerifiedTransaction::new(tx2.transaction.clone(), TransactionOrigin::External).unwrap(); let tx2 = VerifiedTransaction::new(tx2.transaction.clone(), TransactionOrigin::External, None).unwrap();
x.insert(tx1.hash(), tx1); x.insert(tx1.hash(), tx1);
x.insert(tx2.hash(), tx2); x.insert(tx2.hash(), tx2);
x x
@ -1435,12 +1470,12 @@ mod test {
// Create two transactions with same nonce // Create two transactions with same nonce
// (same hash) // (same hash)
let (tx1, tx2) = new_tx_pair_default(0.into(), 0.into()); let (tx1, tx2) = new_tx_pair_default(0.into(), 0.into());
let tx1 = VerifiedTransaction::new(tx1, TransactionOrigin::External).unwrap(); let tx1 = VerifiedTransaction::new(tx1, TransactionOrigin::External, None).unwrap();
let tx2 = VerifiedTransaction::new(tx2, TransactionOrigin::External).unwrap(); let tx2 = VerifiedTransaction::new(tx2, TransactionOrigin::External, None).unwrap();
let by_hash = { let by_hash = {
let mut x = HashMap::new(); let mut x = HashMap::new();
let tx1 = VerifiedTransaction::new(tx1.transaction.clone(), TransactionOrigin::External).unwrap(); let tx1 = VerifiedTransaction::new(tx1.transaction.clone(), TransactionOrigin::External, None).unwrap();
let tx2 = VerifiedTransaction::new(tx2.transaction.clone(), TransactionOrigin::External).unwrap(); let tx2 = VerifiedTransaction::new(tx2.transaction.clone(), TransactionOrigin::External, None).unwrap();
x.insert(tx1.hash(), tx1); x.insert(tx1.hash(), tx1);
x.insert(tx2.hash(), tx2); x.insert(tx2.hash(), tx2);
x x
@ -1482,10 +1517,10 @@ mod test {
gas_limit: !U256::zero(), gas_limit: !U256::zero(),
}; };
let tx = new_tx_default(); let tx = new_tx_default();
let tx1 = VerifiedTransaction::new(tx.clone(), TransactionOrigin::External).unwrap(); let tx1 = VerifiedTransaction::new(tx.clone(), TransactionOrigin::External, None).unwrap();
let order1 = TransactionOrder::for_transaction(&tx1, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly); let order1 = TransactionOrder::for_transaction(&tx1, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly);
assert!(set.insert(tx1.sender(), tx1.nonce(), order1).is_none()); assert!(set.insert(tx1.sender(), tx1.nonce(), order1).is_none());
let tx2 = VerifiedTransaction::new(tx, TransactionOrigin::External).unwrap(); let tx2 = VerifiedTransaction::new(tx, TransactionOrigin::External, None).unwrap();
let order2 = TransactionOrder::for_transaction(&tx2, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly); let order2 = TransactionOrder::for_transaction(&tx2, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly);
assert!(set.insert(tx2.sender(), tx2.nonce(), order2).is_some()); assert!(set.insert(tx2.sender(), tx2.nonce(), order2).is_some());
} }
@ -1502,7 +1537,7 @@ mod test {
assert_eq!(set.gas_price_entry_limit(), 0.into()); assert_eq!(set.gas_price_entry_limit(), 0.into());
let tx = new_tx_default(); let tx = new_tx_default();
let tx1 = VerifiedTransaction::new(tx.clone(), TransactionOrigin::External).unwrap(); let tx1 = VerifiedTransaction::new(tx.clone(), TransactionOrigin::External, None).unwrap();
let order1 = TransactionOrder::for_transaction(&tx1, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly); let order1 = TransactionOrder::for_transaction(&tx1, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly);
assert!(set.insert(tx1.sender(), tx1.nonce(), order1.clone()).is_none()); assert!(set.insert(tx1.sender(), tx1.nonce(), order1.clone()).is_none());
assert_eq!(set.gas_price_entry_limit(), 2.into()); assert_eq!(set.gas_price_entry_limit(), 2.into());
@ -1517,12 +1552,12 @@ mod test {
!U256::zero() }; !U256::zero() };
// First insert one transaction to future // First insert one transaction to future
let res = txq.add(tx, TransactionOrigin::External, &prev_nonce, &gas_estimator); let res = txq.add(tx, TransactionOrigin::External, None, &prev_nonce, &gas_estimator);
assert_eq!(res.unwrap(), TransactionImportResult::Future); assert_eq!(res.unwrap(), TransactionImportResult::Future);
assert_eq!(txq.status().future, 1); assert_eq!(txq.status().future, 1);
// now import second transaction to current // now import second transaction to current
let res = txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator); let res = txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator);
// and then there should be only one transaction in current (the one with higher gas_price) // and then there should be only one transaction in current (the one with higher gas_price)
assert_eq!(res.unwrap(), TransactionImportResult::Current); assert_eq!(res.unwrap(), TransactionImportResult::Current);
@ -1542,12 +1577,12 @@ mod test {
!U256::zero() }; !U256::zero() };
// First insert one transaction to future // First insert one transaction to future
let res = txq.add(tx.clone(), TransactionOrigin::External, &prev_nonce, &gas_estimator); let res = txq.add(tx.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator);
assert_eq!(res.unwrap(), TransactionImportResult::Future); assert_eq!(res.unwrap(), TransactionImportResult::Future);
assert_eq!(txq.status().future, 1); assert_eq!(txq.status().future, 1);
// now import second transaction to current // now import second transaction to current
let res = txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator); let res = txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator);
// then // then
assert_eq!(res.unwrap(), TransactionImportResult::Current); assert_eq!(res.unwrap(), TransactionImportResult::Current);
@ -1566,7 +1601,7 @@ mod test {
let tx = new_tx_default(); let tx = new_tx_default();
// when // when
let res = txq.add(tx, TransactionOrigin::External, &default_account_details, &gas_estimator); let res = txq.add(tx, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
// then // then
assert_eq!(res.unwrap(), TransactionImportResult::Current); assert_eq!(res.unwrap(), TransactionImportResult::Current);
@ -1585,10 +1620,10 @@ mod test {
txq.set_minimal_gas_price(15.into()); txq.set_minimal_gas_price(15.into());
// when // when
let res1 = txq.add(tx1, TransactionOrigin::External, &default_account_details, &gas_estimator); let res1 = txq.add(tx1, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res2 = txq.add(tx2, TransactionOrigin::External, &default_account_details, &gas_estimator); let res2 = txq.add(tx2, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res3 = txq.add(tx3, TransactionOrigin::External, &default_account_details, &gas_estimator); let res3 = txq.add(tx3, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res4 = txq.add(tx4, TransactionOrigin::External, &default_account_details, &gas_estimator); let res4 = txq.add(tx4, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
// then // then
assert_eq!(res1.unwrap(), TransactionImportResult::Current); assert_eq!(res1.unwrap(), TransactionImportResult::Current);
@ -1619,10 +1654,10 @@ mod test {
txq.set_minimal_gas_price(15.into()); txq.set_minimal_gas_price(15.into());
// when // when
let res1 = txq.add(tx1, TransactionOrigin::External, &default_account_details, &gas_estimator); let res1 = txq.add(tx1, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res2 = txq.add(tx2, TransactionOrigin::External, &default_account_details, &gas_estimator); let res2 = txq.add(tx2, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res3 = txq.add(tx3, TransactionOrigin::External, &default_account_details, &gas_estimator); let res3 = txq.add(tx3, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res4 = txq.add(tx4, TransactionOrigin::External, &default_account_details, &gas_estimator); let res4 = txq.add(tx4, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
// then // then
assert_eq!(res1.unwrap(), TransactionImportResult::Current); assert_eq!(res1.unwrap(), TransactionImportResult::Current);
@ -1665,7 +1700,7 @@ mod test {
txq.set_gas_limit(limit); txq.set_gas_limit(limit);
// when // when
let res = txq.add(tx, TransactionOrigin::External, &default_account_details, &gas_estimator); let res = txq.add(tx, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
// then // then
assert_eq!(unwrap_tx_err(res), TransactionError::GasLimitExceeded { assert_eq!(unwrap_tx_err(res), TransactionError::GasLimitExceeded {
@ -1689,7 +1724,7 @@ mod test {
}; };
// when // when
let res = txq.add(tx, TransactionOrigin::External, &account, &gas_estimator); let res = txq.add(tx, TransactionOrigin::External, None, &account, &gas_estimator);
// then // then
assert_eq!(unwrap_tx_err(res), TransactionError::InsufficientBalance { assert_eq!(unwrap_tx_err(res), TransactionError::InsufficientBalance {
@ -1709,7 +1744,7 @@ mod test {
txq.set_minimal_gas_price(tx.gas_price + U256::one()); txq.set_minimal_gas_price(tx.gas_price + U256::one());
// when // when
let res = txq.add(tx, TransactionOrigin::External, &default_account_details, &gas_estimator); let res = txq.add(tx, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
// then // then
assert_eq!(unwrap_tx_err(res), TransactionError::InsufficientGasPrice { assert_eq!(unwrap_tx_err(res), TransactionError::InsufficientGasPrice {
@ -1729,7 +1764,7 @@ mod test {
txq.set_minimal_gas_price(tx.gas_price + U256::one()); txq.set_minimal_gas_price(tx.gas_price + U256::one());
// when // when
let res = txq.add(tx, TransactionOrigin::Local, &default_account_details, &gas_estimator); let res = txq.add(tx, TransactionOrigin::Local, None, &default_account_details, &gas_estimator);
// then // then
assert_eq!(res.unwrap(), TransactionImportResult::Current); assert_eq!(res.unwrap(), TransactionImportResult::Current);
@ -1759,7 +1794,7 @@ mod test {
rlp::decode(s.as_raw()) rlp::decode(s.as_raw())
}; };
// when // when
let res = txq.add(stx, TransactionOrigin::External, &default_account_details, &gas_estimator); let res = txq.add(stx, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
// then // then
assert!(res.is_err()); assert!(res.is_err());
@ -1773,8 +1808,8 @@ mod test {
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
// when // when
txq.add(tx.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// then // then
let top = txq.top_transactions(); let top = txq.top_transactions();
@ -1793,9 +1828,9 @@ mod test {
// when // when
// first insert the one with higher gas price // first insert the one with higher gas price
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// then the one with lower gas price, but local // then the one with lower gas price, but local
txq.add(tx.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap(); txq.add(tx.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
// then // then
let top = txq.top_transactions(); let top = txq.top_transactions();
@ -1812,15 +1847,15 @@ mod test {
// the second one has same nonce but higher `gas_price` // the second one has same nonce but higher `gas_price`
let (_, tx0) = new_similar_tx_pair(); let (_, tx0) = new_similar_tx_pair();
txq.add(tx0.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx0.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// the one with higher gas price is first // the one with higher gas price is first
assert_eq!(txq.top_transactions()[0], tx0); assert_eq!(txq.top_transactions()[0], tx0);
assert_eq!(txq.top_transactions()[1], tx1); assert_eq!(txq.top_transactions()[1], tx1);
// when // when
// insert second as local // insert second as local
txq.add(tx2.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
// then // then
// the order should be updated // the order should be updated
@ -1839,9 +1874,9 @@ mod test {
// when // when
// first insert local one with higher gas price // first insert local one with higher gas price
txq.add(tx2.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
// then the one with lower gas price, but from retracted block // then the one with lower gas price, but from retracted block
txq.add(tx.clone(), TransactionOrigin::RetractedBlock, &default_account_details, &gas_estimator).unwrap(); txq.add(tx.clone(), TransactionOrigin::RetractedBlock, None, &default_account_details, &gas_estimator).unwrap();
// then // then
let top = txq.top_transactions(); let top = txq.top_transactions();
@ -1857,8 +1892,8 @@ mod test {
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
// when // when
txq.add(tx.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
// then // then
let top = txq.top_transactions(); let top = txq.top_transactions();
@ -1877,10 +1912,10 @@ mod test {
let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into()); let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into());
// insert everything // insert everything
txq.add(txa.clone(), TransactionOrigin::External, &prev_nonce, &gas_estimator).unwrap(); txq.add(txa.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
txq.add(txb.clone(), TransactionOrigin::External, &prev_nonce, &gas_estimator).unwrap(); txq.add(txb.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, &prev_nonce, &gas_estimator).unwrap(); txq.add(tx1.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, &prev_nonce, &gas_estimator).unwrap(); txq.add(tx2.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 4); assert_eq!(txq.status().future, 4);
@ -1889,10 +1924,10 @@ mod test {
// then // then
let top = txq.future_transactions(); let top = txq.future_transactions();
assert_eq!(top[0], txa); assert_eq!(top[0].transaction, txa);
assert_eq!(top[1], txb); assert_eq!(top[1].transaction, txb);
assert_eq!(top[2], tx1); assert_eq!(top[2].transaction, tx1);
assert_eq!(top[3], tx2); assert_eq!(top[3].transaction, tx2);
assert_eq!(top.len(), 4); assert_eq!(top.len(), 4);
} }
@ -1905,10 +1940,10 @@ mod test {
let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into()); let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into());
// insert everything // insert everything
txq.add(txa.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap(); txq.add(txa.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(txb.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap(); txq.add(txb.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap(); txq.add(tx1.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
let top = txq.top_transactions(); let top = txq.top_transactions();
assert_eq!(top[0], tx1); assert_eq!(top[0], tx1);
@ -1938,10 +1973,10 @@ mod test {
let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into()); let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into());
// insert everything // insert everything
txq.add(txa.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(txa.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(txb.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(txb.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
let top = txq.top_transactions(); let top = txq.top_transactions();
assert_eq!(top[0], tx1); assert_eq!(top[0], tx1);
@ -1970,8 +2005,8 @@ mod test {
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
// when // when
txq.add(tx.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// then // then
let top = txq.pending_hashes(); let top = txq.pending_hashes();
@ -1988,8 +2023,8 @@ mod test {
let (tx, tx2) = new_tx_pair_default(2.into(), 0.into()); let (tx, tx2) = new_tx_pair_default(2.into(), 0.into());
// when // when
let res1 = txq.add(tx.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); let res1 = txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
let res2 = txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); let res2 = txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// then // then
assert_eq!(res1, TransactionImportResult::Current); assert_eq!(res1, TransactionImportResult::Current);
@ -2002,6 +2037,26 @@ mod test {
assert_eq!(top[0], tx); assert_eq!(top[0], tx);
} }
#[test]
fn should_handle_min_block() {
// given
let mut txq = TransactionQueue::default();
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
// when
let res1 = txq.add(tx.clone(), TransactionOrigin::External, Some(1), &default_account_details, &gas_estimator).unwrap();
let res2 = txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// then
assert_eq!(res1, TransactionImportResult::Current);
assert_eq!(res2, TransactionImportResult::Current);
let top = txq.top_transactions_at(0);
assert_eq!(top.len(), 0);
let top = txq.top_transactions_at(1);
assert_eq!(top.len(), 2);
}
#[test] #[test]
fn should_correctly_update_futures_when_removing() { fn should_correctly_update_futures_when_removing() {
// given // given
@ -2012,8 +2067,8 @@ mod test {
let mut txq = TransactionQueue::default(); let mut txq = TransactionQueue::default();
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
txq.add(tx.clone(), TransactionOrigin::External, &prev_nonce, &gas_estimator).unwrap(); txq.add(tx.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, &prev_nonce, &gas_estimator).unwrap(); txq.add(tx2.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 2); assert_eq!(txq.status().future, 2);
// when // when
@ -2035,13 +2090,13 @@ mod test {
let tx1 = new_unsigned_tx(124.into(), default_gas_val(), 1.into()).sign(secret, None); let tx1 = new_unsigned_tx(124.into(), default_gas_val(), 1.into()).sign(secret, None);
let tx2 = new_unsigned_tx(125.into(), default_gas_val(), 1.into()).sign(secret, None); let tx2 = new_unsigned_tx(125.into(), default_gas_val(), 1.into()).sign(secret, None);
txq.add(tx, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 1); assert_eq!(txq.status().pending, 1);
txq.add(tx2, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 1); assert_eq!(txq.status().future, 1);
// when // when
txq.add(tx1, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx1, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// then // then
let stats = txq.status(); let stats = txq.status();
@ -2057,8 +2112,8 @@ mod test {
// given // given
let mut txq2 = TransactionQueue::default(); let mut txq2 = TransactionQueue::default();
let (tx, tx2) = new_tx_pair_default(3.into(), 0.into()); let (tx, tx2) = new_tx_pair_default(3.into(), 0.into());
txq2.add(tx.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq2.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq2.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq2.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq2.status().pending, 1); assert_eq!(txq2.status().pending, 1);
assert_eq!(txq2.status().future, 1); assert_eq!(txq2.status().future, 1);
@ -2079,10 +2134,10 @@ mod test {
let mut txq = TransactionQueue::default(); let mut txq = TransactionQueue::default();
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
let tx3 = new_tx_default(); let tx3 = new_tx_default();
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 1); assert_eq!(txq.status().future, 1);
txq.add(tx3.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx3.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 3); assert_eq!(txq.status().pending, 3);
// when // when
@ -2101,8 +2156,8 @@ mod test {
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
// add // add
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
let stats = txq.status(); let stats = txq.status();
assert_eq!(stats.pending, 2); assert_eq!(stats.pending, 2);
@ -2121,11 +2176,11 @@ mod test {
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
let sender = tx.sender().unwrap(); let sender = tx.sender().unwrap();
let nonce = tx.nonce; let nonce = tx.nonce;
txq.add(tx.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 1); assert_eq!(txq.status().pending, 1);
// when // when
let res = txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator); let res = txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator);
// then // then
let t = txq.top_transactions(); let t = txq.top_transactions();
@ -2142,14 +2197,14 @@ mod test {
txq.current.set_limit(10); txq.current.set_limit(10);
let (tx1, tx2) = new_tx_pair_default(4.into(), 1.into()); let (tx1, tx2) = new_tx_pair_default(4.into(), 1.into());
let (tx3, tx4) = new_tx_pair_default(4.into(), 2.into()); let (tx3, tx4) = new_tx_pair_default(4.into(), 2.into());
txq.add(tx1.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx3.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 2); assert_eq!(txq.status().pending, 2);
// when // when
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 1); assert_eq!(txq.status().future, 1);
txq.add(tx4.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx4.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// then // then
assert_eq!(txq.status().future, 1); assert_eq!(txq.status().future, 1);
@ -2160,11 +2215,11 @@ mod test {
let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 100, default_gas_val() * U256::from(2), !U256::zero()); let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 100, default_gas_val() * U256::from(2), !U256::zero());
let (tx1, tx2) = new_tx_pair_default(U256::from(1), U256::from(1)); let (tx1, tx2) = new_tx_pair_default(U256::from(1), U256::from(1));
let (tx3, tx4) = new_tx_pair_default(U256::from(1), U256::from(2)); let (tx3, tx4) = new_tx_pair_default(U256::from(1), U256::from(2));
txq.add(tx1.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx3.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// limited by gas // limited by gas
txq.add(tx4.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap_err(); txq.add(tx4.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap_err();
assert_eq!(txq.status().pending, 2); assert_eq!(txq.status().pending, 2);
} }
@ -2174,12 +2229,12 @@ mod test {
let (tx1, tx2) = new_tx_pair_default(U256::from(1), U256::from(1)); let (tx1, tx2) = new_tx_pair_default(U256::from(1), U256::from(1));
let (tx3, tx4) = new_tx_pair_default(U256::from(1), U256::from(2)); let (tx3, tx4) = new_tx_pair_default(U256::from(1), U256::from(2));
let (tx5, _) = new_tx_pair_default(U256::from(1), U256::from(2)); let (tx5, _) = new_tx_pair_default(U256::from(1), U256::from(2));
txq.add(tx1.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap(); txq.add(tx1.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
// Not accepted because of limit // Not accepted because of limit
txq.add(tx5.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap_err(); txq.add(tx5.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap_err();
txq.add(tx3.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap(); txq.add(tx3.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx4.clone(), TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap(); txq.add(tx4.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 4); assert_eq!(txq.status().pending, 4);
} }
@ -2191,7 +2246,7 @@ mod test {
let fetch_last_nonce = |_a: &Address| AccountDetails { nonce: last_nonce, balance: !U256::zero() }; let fetch_last_nonce = |_a: &Address| AccountDetails { nonce: last_nonce, balance: !U256::zero() };
// when // when
let res = txq.add(tx, TransactionOrigin::External, &fetch_last_nonce, &gas_estimator); let res = txq.add(tx, TransactionOrigin::External, None, &fetch_last_nonce, &gas_estimator);
// then // then
assert_eq!(unwrap_tx_err(res), TransactionError::Old); assert_eq!(unwrap_tx_err(res), TransactionError::Old);
@ -2207,12 +2262,12 @@ mod test {
balance: !U256::zero() }; balance: !U256::zero() };
let mut txq = TransactionQueue::default(); let mut txq = TransactionQueue::default();
let (_tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); let (_tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 1); assert_eq!(txq.status().future, 1);
assert_eq!(txq.status().pending, 0); assert_eq!(txq.status().pending, 0);
// when // when
let res = txq.add(tx2.clone(), TransactionOrigin::External, &nonce, &gas_estimator); let res = txq.add(tx2.clone(), TransactionOrigin::External, None, &nonce, &gas_estimator);
// then // then
assert_eq!(unwrap_tx_err(res), TransactionError::AlreadyImported); assert_eq!(unwrap_tx_err(res), TransactionError::AlreadyImported);
@ -2226,15 +2281,15 @@ mod test {
// given // given
let mut txq = TransactionQueue::default(); let mut txq = TransactionQueue::default();
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
txq.add(tx1.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 2); assert_eq!(txq.status().pending, 2);
// when // when
txq.remove_invalid(&tx1.hash(), &default_account_details); txq.remove_invalid(&tx1.hash(), &default_account_details);
assert_eq!(txq.status().pending, 0); assert_eq!(txq.status().pending, 0);
assert_eq!(txq.status().future, 1); assert_eq!(txq.status().future, 1);
txq.add(tx1.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// then // then
let stats = txq.status(); let stats = txq.status();
@ -2248,10 +2303,10 @@ mod test {
let mut txq = TransactionQueue::default(); let mut txq = TransactionQueue::default();
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into()); let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
let tx3 = new_tx_default(); let tx3 = new_tx_default();
txq.add(tx2.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 1); assert_eq!(txq.status().future, 1);
txq.add(tx3.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx3.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 3); assert_eq!(txq.status().pending, 3);
// when // when
@ -2278,8 +2333,8 @@ mod test {
}; };
// when // when
txq.add(tx, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// then // then
let stats = txq.status(); let stats = txq.status();
@ -2306,10 +2361,10 @@ mod test {
}; };
// when // when
txq.add(tx1, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx1, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 1); assert_eq!(txq.status().future, 1);
txq.add(tx0, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx0, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
// then // then
let stats = txq.status(); let stats = txq.status();
@ -2327,8 +2382,8 @@ mod test {
!U256::zero() }; !U256::zero() };
let mut txq = TransactionQueue::default(); let mut txq = TransactionQueue::default();
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into()); let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
txq.add(tx1.clone(), TransactionOrigin::External, &previous_nonce, &gas_estimator).unwrap(); txq.add(tx1.clone(), TransactionOrigin::External, None, &previous_nonce, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, &previous_nonce, &gas_estimator).unwrap(); txq.add(tx2, TransactionOrigin::External, None, &previous_nonce, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 2); assert_eq!(txq.status().future, 2);
// when // when
@ -2359,7 +2414,7 @@ mod test {
let details = |_a: &Address| AccountDetails { nonce: nonce, balance: !U256::zero() }; let details = |_a: &Address| AccountDetails { nonce: nonce, balance: !U256::zero() };
// when // when
txq.add(tx, TransactionOrigin::External, &details, &gas_estimator).unwrap(); txq.add(tx, TransactionOrigin::External, None, &details, &gas_estimator).unwrap();
// then // then
assert_eq!(txq.last_nonce(&from), Some(nonce)); assert_eq!(txq.last_nonce(&from), Some(nonce));
@ -2374,7 +2429,7 @@ mod test {
let details1 = |_a: &Address| AccountDetails { nonce: nonce1, balance: !U256::zero() }; let details1 = |_a: &Address| AccountDetails { nonce: nonce1, balance: !U256::zero() };
// Insert first transaction // Insert first transaction
txq.add(tx1, TransactionOrigin::External, &details1, &gas_estimator).unwrap(); txq.add(tx1, TransactionOrigin::External, None, &details1, &gas_estimator).unwrap();
// when // when
txq.remove_all(tx2.sender().unwrap(), nonce2 + U256::one()); txq.remove_all(tx2.sender().unwrap(), nonce2 + U256::one());
@ -2394,9 +2449,9 @@ mod test {
// when // when
// Insert first transaction // Insert first transaction
assert_eq!(txq.add(tx1, TransactionOrigin::External, &details1, &gas_estimator).unwrap(), TransactionImportResult::Current); assert_eq!(txq.add(tx1, TransactionOrigin::External, None, &details1, &gas_estimator).unwrap(), TransactionImportResult::Current);
// Second should go to future // Second should go to future
assert_eq!(txq.add(tx2, TransactionOrigin::External, &details1, &gas_estimator).unwrap(), TransactionImportResult::Future); assert_eq!(txq.add(tx2, TransactionOrigin::External, None, &details1, &gas_estimator).unwrap(), TransactionImportResult::Future);
// Now block is imported // Now block is imported
txq.remove_all(sender, nonce2 - U256::from(1)); txq.remove_all(sender, nonce2 - U256::from(1));
// tx2 should be not be promoted to current // tx2 should be not be promoted to current
@ -2415,9 +2470,9 @@ mod test {
assert_eq!(txq.has_local_pending_transactions(), false); assert_eq!(txq.has_local_pending_transactions(), false);
// when // when
assert_eq!(txq.add(tx1, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(), TransactionImportResult::Current); assert_eq!(txq.add(tx1, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap(), TransactionImportResult::Current);
assert_eq!(txq.has_local_pending_transactions(), false); assert_eq!(txq.has_local_pending_transactions(), false);
assert_eq!(txq.add(tx2, TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap(), TransactionImportResult::Current); assert_eq!(txq.add(tx2, TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap(), TransactionImportResult::Current);
// then // then
assert_eq!(txq.has_local_pending_transactions(), true); assert_eq!(txq.has_local_pending_transactions(), true);
@ -2432,8 +2487,8 @@ mod test {
default_account_details(a).balance }; default_account_details(a).balance };
// when // when
assert_eq!(txq.add(tx2, TransactionOrigin::External, &prev_nonce, &gas_estimator).unwrap(), TransactionImportResult::Future); assert_eq!(txq.add(tx2, TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap(), TransactionImportResult::Future);
assert_eq!(txq.add(tx1.clone(), TransactionOrigin::External, &prev_nonce, &gas_estimator).unwrap(), TransactionImportResult::Future); assert_eq!(txq.add(tx1.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap(), TransactionImportResult::Future);
// then // then
assert_eq!(txq.future.by_priority.len(), 1); assert_eq!(txq.future.by_priority.len(), 1);
@ -2458,14 +2513,14 @@ mod test {
(tx.sign(secret, None), tx2.sign(secret, None), tx2_2.sign(secret, None), tx3.sign(secret, None)) (tx.sign(secret, None), tx2.sign(secret, None), tx2_2.sign(secret, None), tx3.sign(secret, None))
}; };
let sender = tx1.sender().unwrap(); let sender = tx1.sender().unwrap();
txq.add(tx1, TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap(); txq.add(tx1, TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2, TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3, TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap(); txq.add(tx3, TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.future.by_priority.len(), 0); assert_eq!(txq.future.by_priority.len(), 0);
assert_eq!(txq.current.by_priority.len(), 3); assert_eq!(txq.current.by_priority.len(), 3);
// when // when
let res = txq.add(tx2_2, TransactionOrigin::Local, &default_account_details, &gas_estimator); let res = txq.add(tx2_2, TransactionOrigin::Local, None, &default_account_details, &gas_estimator);
// then // then
assert_eq!(txq.last_nonce(&sender).unwrap(), 125.into()); assert_eq!(txq.last_nonce(&sender).unwrap(), 125.into());
@ -2481,8 +2536,8 @@ mod test {
let high_gas = |_: &SignedTransaction| 100_001.into(); let high_gas = |_: &SignedTransaction| 100_001.into();
// when // when
let res1 = txq.add(tx1, TransactionOrigin::Local, &default_account_details, &gas_estimator); let res1 = txq.add(tx1, TransactionOrigin::Local, None, &default_account_details, &gas_estimator);
let res2 = txq.add(tx2, TransactionOrigin::Local, &default_account_details, &high_gas); let res2 = txq.add(tx2, TransactionOrigin::Local, None, &default_account_details, &high_gas);
// then // then
assert_eq!(res1.unwrap(), TransactionImportResult::Current); assert_eq!(res1.unwrap(), TransactionImportResult::Current);
@ -2502,10 +2557,10 @@ mod test {
let nonce1 = tx1.nonce; let nonce1 = tx1.nonce;
// Insert all transactions // Insert all transactions
txq.add(tx1, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx1, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx2, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx3, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx4, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx4, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.top_transactions().len(), 4); assert_eq!(txq.top_transactions().len(), 4);
// when // when

View File

@ -81,9 +81,6 @@ impl ClientService {
panic_handler.forward_from(&io_service); panic_handler.forward_from(&io_service);
info!("Configured for {} using {} engine", Colour::White.bold().paint(spec.name.clone()), Colour::Yellow.bold().paint(spec.engine.name())); info!("Configured for {} using {} engine", Colour::White.bold().paint(spec.name.clone()), Colour::Yellow.bold().paint(spec.engine.name()));
if spec.fork_name.is_some() {
warn!("Your chain is an alternative fork. {}", Colour::Red.bold().paint("TRANSACTIONS MAY BE REPLAYED ON THE MAINNET!"));
}
let mut db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS); let mut db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS);

View File

@ -44,6 +44,16 @@ pub struct AuthorityRound {
pub signature: H520, pub signature: H520,
} }
/// Tendermint seal.
pub struct Tendermint {
/// Seal round.
pub round: usize,
/// Proposal seal signature.
pub proposal: H520,
/// Precommit seal signatures.
pub precommits: Vec<H520>,
}
impl Into<Generic> for AuthorityRound { impl Into<Generic> for AuthorityRound {
fn into(self) -> Generic { fn into(self) -> Generic {
let mut s = RlpStream::new_list(2); let mut s = RlpStream::new_list(2);
@ -52,6 +62,14 @@ impl Into<Generic> for AuthorityRound {
} }
} }
impl Into<Generic> for Tendermint {
fn into(self) -> Generic {
let mut s = RlpStream::new_list(3);
s.append(&self.round).append(&self.proposal).append(&self.precommits);
Generic(s.out())
}
}
pub struct Generic(pub Vec<u8>); pub struct Generic(pub Vec<u8>);
/// Genesis seal type. /// Genesis seal type.
@ -60,6 +78,8 @@ pub enum Seal {
Ethereum(Ethereum), Ethereum(Ethereum),
/// AuthorityRound seal. /// AuthorityRound seal.
AuthorityRound(AuthorityRound), AuthorityRound(AuthorityRound),
/// Tendermint seal.
Tendermint(Tendermint),
/// Generic RLP seal. /// Generic RLP seal.
Generic(Generic), Generic(Generic),
} }
@ -75,6 +95,11 @@ impl From<ethjson::spec::Seal> for Seal {
step: ar.step.into(), step: ar.step.into(),
signature: ar.signature.into() signature: ar.signature.into()
}), }),
ethjson::spec::Seal::Tendermint(tender) => Seal::Tendermint(Tendermint {
round: tender.round.into(),
proposal: tender.proposal.into(),
precommits: tender.precommits.into_iter().map(Into::into).collect()
}),
ethjson::spec::Seal::Generic(g) => Seal::Generic(Generic(g.into())), ethjson::spec::Seal::Generic(g) => Seal::Generic(Generic(g.into())),
} }
} }
@ -86,6 +111,7 @@ impl Into<Generic> for Seal {
Seal::Generic(generic) => generic, Seal::Generic(generic) => generic,
Seal::Ethereum(eth) => eth.into(), Seal::Ethereum(eth) => eth.into(),
Seal::AuthorityRound(ar) => ar.into(), Seal::AuthorityRound(ar) => ar.into(),
Seal::Tendermint(tender) => tender.into(),
} }
} }
} }

View File

@ -66,8 +66,8 @@ pub struct Spec {
pub name: String, pub name: String,
/// What engine are we using for this? /// What engine are we using for this?
pub engine: Arc<Engine>, pub engine: Arc<Engine>,
/// The fork identifier for this chain. Only needed to distinguish two chains sharing the same genesis. /// Name of the subdir inside the main data dir to use for chain data and settings.
pub fork_name: Option<String>, pub data_dir: String,
/// Known nodes on the network in enode format. /// Known nodes on the network in enode format.
pub nodes: Vec<String>, pub nodes: Vec<String>,
@ -110,10 +110,10 @@ impl From<ethjson::spec::Spec> for Spec {
let GenericSeal(seal_rlp) = g.seal.into(); let GenericSeal(seal_rlp) = g.seal.into();
let params = CommonParams::from(s.params); let params = CommonParams::from(s.params);
Spec { Spec {
name: s.name.into(), name: s.name.clone().into(),
params: params.clone(), params: params.clone(),
engine: Spec::engine(s.engine, params, builtins), engine: Spec::engine(s.engine, params, builtins),
fork_name: s.fork_name.map(Into::into), data_dir: s.data_dir.unwrap_or(s.name).into(),
nodes: s.nodes.unwrap_or_else(Vec::new), nodes: s.nodes.unwrap_or_else(Vec::new),
parent_hash: g.parent_hash, parent_hash: g.parent_hash,
transactions_root: g.transactions_root, transactions_root: g.transactions_root,

View File

@ -28,6 +28,9 @@ use rlp::{Rlp, View};
use spec::Spec; use spec::Spec;
use views::BlockView; use views::BlockView;
use util::stats::Histogram; use util::stats::Histogram;
use ethkey::KeyPair;
use transaction::{PendingTransaction, Transaction, Action};
use miner::MinerService;
#[test] #[test]
fn imports_from_empty() { fn imports_from_empty() {
@ -284,3 +287,37 @@ fn change_history_size() {
let client = Client::new(config, &test_spec, dir.as_path(), Arc::new(Miner::with_spec(&test_spec)), IoChannel::disconnected(), &db_config).unwrap(); let client = Client::new(config, &test_spec, dir.as_path(), Arc::new(Miner::with_spec(&test_spec)), IoChannel::disconnected(), &db_config).unwrap();
assert_eq!(client.state().balance(&address), 100.into()); assert_eq!(client.state().balance(&address), 100.into());
} }
#[test]
fn does_not_propagate_delayed_transactions() {
let key = KeyPair::from_secret("test".sha3()).unwrap();
let secret = key.secret();
let tx0 = PendingTransaction::new(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 21000.into(),
action: Action::Call(Address::default()),
value: 0.into(),
data: Vec::new(),
}.sign(secret, None), Some(2));
let tx1 = PendingTransaction::new(Transaction {
nonce: 1.into(),
gas_price: 0.into(),
gas: 21000.into(),
action: Action::Call(Address::default()),
value: 0.into(),
data: Vec::new(),
}.sign(secret, None), None);
let client_result = generate_dummy_client(1);
let client = client_result.reference();
client.miner().import_own_transaction(&**client, tx0).unwrap();
client.miner().import_own_transaction(&**client, tx1).unwrap();
assert_eq!(0, client.ready_transactions().len());
assert_eq!(2, client.miner().pending_transactions().len());
push_blocks_to_client(client, 53, 2, 2);
client.flush_queue();
assert_eq!(2, client.ready_transactions().len());
assert_eq!(2, client.miner().pending_transactions().len());
}

View File

@ -18,6 +18,7 @@
use util::{U256, H256}; use util::{U256, H256};
use header::BlockNumber; use header::BlockNumber;
use types::security_level::SecurityLevel;
/// Information about the blockchain gathered together. /// Information about the blockchain gathered together.
#[derive(Clone, Debug, Binary)] #[derive(Clone, Debug, Binary)]
@ -41,3 +42,15 @@ pub struct BlockChainInfo {
/// Number of the first block on the best sequence. /// Number of the first block on the best sequence.
pub first_block_number: Option<BlockNumber>, pub first_block_number: Option<BlockNumber>,
} }
impl BlockChainInfo {
/// Determine the security model for the current state.
pub fn security_level(&self) -> SecurityLevel {
// TODO: Detect SecurityLevel::FullState : https://github.com/ethcore/parity/issues/3834
if self.ancient_block_number.is_none() || self.first_block_number.is_none() {
SecurityLevel::FullProofOfWork
} else {
SecurityLevel::PartialProofOfWork(self.best_block_number - self.first_block_number.expect("Guard condition means this is not none"))
}
}
}

View File

@ -35,3 +35,4 @@ pub mod restoration_status;
pub mod snapshot_manifest; pub mod snapshot_manifest;
pub mod mode; pub mod mode;
pub mod pruning_info; pub mod pruning_info;
pub mod security_level;

View File

@ -0,0 +1,40 @@
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Indication of how secure the chain is.
use header::BlockNumber;
/// Indication of how secure the chain is.
#[derive(Debug, PartialEq, Copy, Clone, Hash, Eq, Binary)]
pub enum SecurityLevel {
/// All blocks from genesis to chain head are known to have valid state transitions and PoW.
FullState,
/// All blocks from genesis to chain head are known to have a valid PoW.
FullProofOfWork,
/// Some recent headers (the argument) are known to have a valid PoW.
PartialProofOfWork(BlockNumber),
}
impl SecurityLevel {
/// `true` for `FullPoW`/`FullState`.
pub fn is_full(&self) -> bool {
match *self {
SecurityLevel::FullState | SecurityLevel::FullProofOfWork => true,
_ => false,
}
}
}

View File

@ -21,7 +21,7 @@ use super::trace::{Action, Res};
use header::BlockNumber; use header::BlockNumber;
/// Localized trace. /// Localized trace.
#[derive(Debug, PartialEq, Binary)] #[derive(Debug, PartialEq, Clone, Binary)]
pub struct LocalizedTrace { pub struct LocalizedTrace {
/// Type of action performed by a transaction. /// Type of action performed by a transaction.
pub action: Action, pub action: Action,

View File

@ -390,6 +390,34 @@ impl Deref for LocalizedTransaction {
} }
} }
/// Queued transaction with additional information.
#[derive(Debug, Clone, PartialEq, Eq, Binary)]
pub struct PendingTransaction {
/// Signed transaction data.
pub transaction: SignedTransaction,
/// To be activated at this block. `None` for immediately.
pub min_block: Option<BlockNumber>,
}
impl PendingTransaction {
/// Create a new pending transaction from signed transaction.
pub fn new(signed: SignedTransaction, min_block: Option<BlockNumber>) -> Self {
PendingTransaction {
transaction: signed,
min_block: min_block,
}
}
}
impl From<SignedTransaction> for PendingTransaction {
fn from(t: SignedTransaction) -> Self {
PendingTransaction {
transaction: t,
min_block: None,
}
}
}
#[test] #[test]
fn sender_test() { fn sender_test() {
let t: SignedTransaction = decode(&::rustc_serialize::hex::FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap()); let t: SignedTransaction = decode(&::rustc_serialize::hex::FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap());

View File

@ -486,7 +486,13 @@ impl<K: Kind> VerificationQueue<K> {
Ok(h) Ok(h)
}, },
Err(err) => { Err(err) => {
self.verification.bad.lock().insert(h.clone()); match err {
// Don't mark future blocks as bad.
Error::Block(BlockError::InvalidTimestamp(ref e)) if e.max.is_some() => {},
_ => {
self.verification.bad.lock().insert(h.clone());
}
}
Err(err) Err(err)
} }
} }
@ -681,8 +687,12 @@ impl<K: Kind> Drop for VerificationQueue<K> {
*self.state.0.lock() = State::Exit; *self.state.0.lock() = State::Exit;
self.state.1.notify_all(); self.state.1.notify_all();
// wake up all threads waiting for more work. // acquire this lock to force threads to reach the waiting point
self.more_to_verify.notify_all(); // if they're in-between the exit check and the more_to_verify wait.
{
let _more = self.verification.more_to_verify.lock().unwrap();
self.more_to_verify.notify_all();
}
// wait for all verifier threads to join. // wait for all verifier threads to join.
for thread in self.verifier_handles.drain(..) { for thread in self.verifier_handles.drain(..) {

View File

@ -2,7 +2,7 @@
description = "Fetching hash-addressed content." description = "Fetching hash-addressed content."
homepage = "http://parity.io" homepage = "http://parity.io"
license = "GPL-3.0" license = "GPL-3.0"
name = "ethcore-hash-fetch" name = "parity-hash-fetch"
version = "1.5.0" version = "1.5.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
@ -11,5 +11,5 @@ log = "0.3"
rustc-serialize = "0.3" rustc-serialize = "0.3"
ethabi = "0.2.2" ethabi = "0.2.2"
mime_guess = "1.6.1" mime_guess = "1.6.1"
fetch = { path = "../../util/fetch" } fetch = { path = "../util/fetch" }
ethcore-util = { path = "../../util" } ethcore-util = { path = "../util" }

View File

@ -26,7 +26,7 @@ use fetch::{Fetch, FetchError, Client as FetchClient};
use urlhint::{ContractClient, URLHintContract, URLHint, URLHintResult}; use urlhint::{ContractClient, URLHintContract, URLHint, URLHintResult};
/// API for fetching by hash. /// API for fetching by hash.
pub trait HashFetch { pub trait HashFetch: Send + Sync + 'static {
/// Fetch hash-addressed content. /// Fetch hash-addressed content.
/// Parameters: /// Parameters:
/// 1. `hash` - content hash /// 1. `hash` - content hash
@ -42,7 +42,12 @@ pub enum Error {
/// Hash could not be resolved to a valid content address. /// Hash could not be resolved to a valid content address.
NoResolution, NoResolution,
/// Downloaded content hash does not match. /// Downloaded content hash does not match.
HashMismatch { expected: H256, got: H256 }, HashMismatch {
/// Expected hash
expected: H256,
/// Computed hash
got: H256,
},
/// IO Error while validating hash. /// IO Error while validating hash.
IO(io::Error), IO(io::Error),
/// Error during fetch. /// Error during fetch.
@ -79,7 +84,7 @@ impl Client {
impl HashFetch for Client { impl HashFetch for Client {
fn fetch(&self, hash: H256, on_done: Box<Fn(Result<PathBuf, Error>) + Send>) -> Result<(), Error> { fn fetch(&self, hash: H256, on_done: Box<Fn(Result<PathBuf, Error>) + Send>) -> Result<(), Error> {
debug!(target: "dapps", "Fetching: {:?}", hash); debug!(target: "fetch", "Fetching: {:?}", hash);
let url = try!( let url = try!(
self.contract.resolve(hash.to_vec()).map(|content| match content { self.contract.resolve(hash.to_vec()).map(|content| match content {
@ -92,7 +97,7 @@ impl HashFetch for Client {
}).ok_or_else(|| Error::NoResolution) }).ok_or_else(|| Error::NoResolution)
); );
debug!(target: "dapps", "Resolved {:?} to {:?}. Fetching...", hash, url); debug!(target: "fetch", "Resolved {:?} to {:?}. Fetching...", hash, url);
self.fetch.lock().request_async(&url, Default::default(), Box::new(move |result| { self.fetch.lock().request_async(&url, Default::default(), Box::new(move |result| {
fn validate_hash(hash: H256, result: Result<PathBuf, FetchError>) -> Result<PathBuf, Error> { fn validate_hash(hash: H256, result: Result<PathBuf, FetchError>) -> Result<PathBuf, Error> {
@ -107,7 +112,7 @@ impl HashFetch for Client {
} }
} }
debug!(target: "dapps", "Content fetched, validating hash ({:?})", hash); debug!(target: "fetch", "Content fetched, validating hash ({:?})", hash);
on_done(validate_hash(hash, result)) on_done(validate_hash(hash, result))
})).map_err(Into::into) })).map_err(Into::into)
} }

View File

@ -30,4 +30,4 @@ mod client;
pub mod urlhint; pub mod urlhint;
pub use client::{HashFetch, Client}; pub use client::{HashFetch, Client, Error};

View File

@ -0,0 +1,20 @@
[package]
description = "Types that implement IPC and are common to multiple modules."
name = "ipc-common-types"
version = "1.5.0"
license = "GPL-3.0"
authors = ["Parity Technologies <admin@parity.io>"]
build = "build.rs"
[build-dependencies]
ethcore-ipc-codegen = { path = "../ipc/codegen" }
[dependencies]
log = "0.3"
semver = "0.5"
ethcore-ipc = { path = "../ipc/rpc" }
ethcore-util = { path = "../util" }
[profile.release]
debug = true
lto = false

21
ipc-common-types/build.rs Normal file
View File

@ -0,0 +1,21 @@
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
extern crate ethcore_ipc_codegen;
fn main() {
ethcore_ipc_codegen::derive_binary("src/types/mod.rs.in").unwrap();
}

View File

@ -0,0 +1,26 @@
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Updater for Parity executables
#[macro_use] extern crate log;
extern crate semver;
extern crate ethcore_util as util;
extern crate ethcore_ipc as ipc;
mod types;
pub use types::*;

View File

@ -0,0 +1,21 @@
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Types used in the public api
#![allow(dead_code, unused_assignments, unused_variables)] // codegen issues
include!(concat!(env!("OUT_DIR"), "/mod.rs.in"));

View File

@ -0,0 +1,21 @@
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
pub mod release_track;
pub mod version_info;
pub use release_track::{ReleaseTrack};
pub use version_info::{VersionInfo};

View File

@ -0,0 +1,82 @@
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Types used in the public API
use std::fmt;
/// A release's track.
#[derive(PartialEq, Eq, Clone, Copy, Debug, Binary)]
pub enum ReleaseTrack {
/// Stable track.
Stable,
/// Beta track.
Beta,
/// Nightly track.
Nightly,
/// Testing track.
Testing,
/// No known track, also "current executable's track" when it's not yet known.
Unknown,
}
impl fmt::Display for ReleaseTrack {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}", match *self {
ReleaseTrack::Stable => "stable",
ReleaseTrack::Beta => "beta",
ReleaseTrack::Nightly => "nightly",
ReleaseTrack::Testing => "testing",
ReleaseTrack::Unknown => "unknown",
})
}
}
impl<'a> From<&'a str> for ReleaseTrack {
fn from(s: &'a str) -> Self {
match s {
"stable" => ReleaseTrack::Stable,
"beta" => ReleaseTrack::Beta,
"nightly" => ReleaseTrack::Nightly,
"testing" => ReleaseTrack::Testing,
_ => ReleaseTrack::Unknown,
}
}
}
impl From<u8> for ReleaseTrack {
fn from(i: u8) -> Self {
match i {
1 => ReleaseTrack::Stable,
2 => ReleaseTrack::Beta,
3 => ReleaseTrack::Nightly,
4 => ReleaseTrack::Testing,
_ => ReleaseTrack::Unknown,
}
}
}
impl Into<u8> for ReleaseTrack {
fn into(self) -> u8 {
match self {
ReleaseTrack::Stable => 1,
ReleaseTrack::Beta => 2,
ReleaseTrack::Nightly => 3,
ReleaseTrack::Testing => 4,
ReleaseTrack::Unknown => 0,
}
}
}

View File

@ -0,0 +1,68 @@
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Types used in the public API
use std::fmt;
use semver::{Version};
use util::{H160};
use util::misc::raw_package_info;
use release_track::ReleaseTrack;
/// Version information of a particular release.
#[derive(Debug, Clone, PartialEq, Binary)]
pub struct VersionInfo {
/// The track on which it was released.
pub track: ReleaseTrack,
/// The version.
pub version: Version,
/// The (SHA1?) 160-bit hash of this build's code base.
pub hash: H160,
}
impl fmt::Display for VersionInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}.{}.{}-{}-{}", self.version.major, self.version.minor, self.version.patch, self.track, self.hash)
}
}
impl VersionInfo {
/// Get information for this (currently running) binary.
pub fn this() -> Self {
let raw = raw_package_info();
VersionInfo {
track: raw.0.into(),
version: { let mut v = Version::parse(raw.1).expect("Environment variables are known to be valid; qed"); v.build = vec![]; v.pre = vec![]; v },
hash: raw.2.into(),
}
}
/// Compose the information from the provided raw fields.
pub fn from_raw(semver: u32, track: u8, hash: H160) -> Self {
let t = track.into();
VersionInfo {
version: Version {
major: (semver >> 16) as u64,
minor: ((semver >> 8) & 0xff) as u64,
patch: (semver & 0xff) as u64,
build: vec![],
pre: vec![],
},
track: t,
hash: hash,
}
}
}

View File

@ -263,7 +263,7 @@ fn binary_expr_struct(
let range_ident = builder.id(format!("r{}", index)); let range_ident = builder.id(format!("r{}", index));
let error_message = "Error serializing member: ".to_owned() + &::syntax::print::pprust::expr_to_string(&member_expr); let error_message = "Error serializing member: ".to_owned() + &::syntax::print::pprust::expr_to_string(&member_expr);
let error_message_literal = builder.expr().lit().str::<&str>(&error_message); let _error_message_literal = builder.expr().lit().str::<&str>(&error_message);
match raw_ident.as_ref() { match raw_ident.as_ref() {
"u8" => { "u8" => {
@ -286,7 +286,6 @@ fn binary_expr_struct(
post_write_stmts.push(quote_stmt!(cx, post_write_stmts.push(quote_stmt!(cx,
if $range_ident.end - $range_ident.start > 0 { if $range_ident.end - $range_ident.start > 0 {
if let Err(e) = $member_expr .to_bytes(&mut buffer[$range_ident], length_stack) { if let Err(e) = $member_expr .to_bytes(&mut buffer[$range_ident], length_stack) {
warn!(target: "ipc", $error_message_literal);
return Err(e) return Err(e)
}; };
} }

View File

@ -11,7 +11,7 @@ build = "build.rs"
ethcore-ipc = { path = "../rpc" } ethcore-ipc = { path = "../rpc" }
nanomsg = { git = "https://github.com/ethcore/nanomsg.rs.git" } nanomsg = { git = "https://github.com/ethcore/nanomsg.rs.git" }
ethcore-ipc-nano = { path = "../nano" } ethcore-ipc-nano = { path = "../nano" }
semver = "0.2" semver = "0.5"
log = "0.3" log = "0.3"
time = "0.1" time = "0.1"

View File

@ -10,4 +10,4 @@ license = "GPL-3.0"
ethcore-devtools = { path = "../../devtools" } ethcore-devtools = { path = "../../devtools" }
nanomsg = { git = "https://github.com/ethcore/nanomsg.rs.git" } nanomsg = { git = "https://github.com/ethcore/nanomsg.rs.git" }
ethcore-util = { path = "../../util" } ethcore-util = { path = "../../util" }
semver = "0.2" semver = "0.5"

View File

@ -804,6 +804,17 @@ binary_fixed_size!(H512);
binary_fixed_size!(H2048); binary_fixed_size!(H2048);
binary_fixed_size!(Address); binary_fixed_size!(Address);
binary_fixed_size!(BinHandshake); binary_fixed_size!(BinHandshake);
binary_fixed_size!(BinVersion);
impl BinaryConvertable for ::semver::Version {
fn from_bytes(bytes: &[u8], length_stack: &mut ::std::collections::VecDeque<usize>) -> Result<Self, BinaryConvertError> {
BinVersion::from_bytes(bytes, length_stack).map(BinVersion::to_semver)
}
fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut ::std::collections::VecDeque<usize>) -> Result<(), BinaryConvertError> {
BinVersion::from(self.clone()).to_bytes(buffer, length_stack)
}
}
#[test] #[test]
fn vec_serialize() { fn vec_serialize() {

View File

@ -24,4 +24,4 @@ extern crate ethcore_util as util;
pub mod interface; pub mod interface;
pub mod binary; pub mod binary;
pub use interface::{IpcInterface, IpcSocket, invoke, IpcConfig, Handshake, Error, WithSocket}; pub use interface::{IpcInterface, IpcSocket, invoke, IpcConfig, Handshake, Error, WithSocket};
pub use binary::{BinaryConvertable, BinaryConvertError, BinHandshake}; pub use binary::{BinaryConvertable, BinaryConvertError, BinVersion, BinHandshake};

View File

@ -10,7 +10,7 @@ path = "run.rs"
[dependencies] [dependencies]
ethcore-ipc = { path = "../rpc" } ethcore-ipc = { path = "../rpc" }
ethcore-devtools = { path = "../../devtools" } ethcore-devtools = { path = "../../devtools" }
semver = "0.2" semver = "0.5"
nanomsg = { git = "https://github.com/ethcore/nanomsg.rs.git" } nanomsg = { git = "https://github.com/ethcore/nanomsg.rs.git" }
ethcore-ipc-nano = { path = "../nano" } ethcore-ipc-nano = { path = "../nano" }
ethcore-util = { path = "../../util" } ethcore-util = { path = "../../util" }

View File

@ -1,6 +1,6 @@
{ {
"name": "parity.js", "name": "parity.js",
"version": "0.2.122", "version": "0.2.130",
"main": "release/index.js", "main": "release/index.js",
"jsnext:main": "src/index.js", "jsnext:main": "src/index.js",
"author": "Parity Team <admin@parity.io>", "author": "Parity Team <admin@parity.io>",
@ -36,7 +36,7 @@
"ci:build:npm": "NODE_ENV=production webpack --config webpack/npm", "ci:build:npm": "NODE_ENV=production webpack --config webpack/npm",
"start": "npm install && npm run build:lib && npm run build:dll && npm run start:app", "start": "npm install && npm run build:lib && npm run build:dll && npm run start:app",
"start:app": "node webpack/dev.server", "start:app": "node webpack/dev.server",
"clean": "rm -rf ./build ./coverage", "clean": "rm -rf ./.build ./.coverage ./.happypack ./.npmjs ./build",
"coveralls": "npm run testCoverage && coveralls < coverage/lcov.info", "coveralls": "npm run testCoverage && coveralls < coverage/lcov.info",
"lint": "npm run lint:css && npm run lint:js", "lint": "npm run lint:css && npm run lint:js",
"lint:cached": "npm run lint:css && npm run lint:js:cached", "lint:cached": "npm run lint:css && npm run lint:js:cached",
@ -136,6 +136,7 @@
"blockies": "0.0.2", "blockies": "0.0.2",
"brace": "0.9.0", "brace": "0.9.0",
"bytes": "2.4.0", "bytes": "2.4.0",
"debounce": "1.0.0",
"es6-error": "4.0.0", "es6-error": "4.0.0",
"es6-promise": "4.0.5", "es6-promise": "4.0.5",
"ethereumjs-tx": "1.1.4", "ethereumjs-tx": "1.1.4",

View File

@ -342,7 +342,8 @@ export default class Contract {
options: _options, options: _options,
autoRemove, autoRemove,
callback, callback,
filterId filterId,
id: subscriptionId
}; };
if (skipInitFetch) { if (skipInitFetch) {
@ -452,13 +453,13 @@ export default class Contract {
}) })
) )
.then((logsArray) => { .then((logsArray) => {
logsArray.forEach((logs, subscriptionId) => { logsArray.forEach((logs, index) => {
if (!logs || !logs.length) { if (!logs || !logs.length) {
return; return;
} }
try { try {
this.sendData(subscriptionId, null, this.parseEventLogs(logs)); this._sendData(subscriptions[index].id, null, this.parseEventLogs(logs));
} catch (error) { } catch (error) {
console.error('_sendSubscriptionChanges', error); console.error('_sendSubscriptionChanges', error);
} }

View File

@ -110,7 +110,8 @@ export function outPeers (peers) {
return { return {
active: outNumber(peers.active), active: outNumber(peers.active),
connected: outNumber(peers.connected), connected: outNumber(peers.connected),
max: outNumber(peers.max) max: outNumber(peers.max),
peers: peers.peers.map(p => { Object.keys(p.protocols).forEach(k => { p.protocols[k].difficulty = outNumber(p.protocols[k].difficulty); }); return p; })
}; };
} }

View File

@ -147,10 +147,50 @@ describe('api/format/output', () => {
describe('outPeers', () => { describe('outPeers', () => {
it('converts all internal numbers to BigNumbers', () => { it('converts all internal numbers to BigNumbers', () => {
expect(outPeers({ active: 789, connected: '456', max: 0x7b })).to.deep.equal({ expect(outPeers({
active: 789,
connected: '456',
max: 0x7b,
peers: [
{
caps: ['par/1'],
id: '0x01',
name: 'Parity',
network: {
localAddress: '10.0.0.1',
remoteAddress: '10.0.0.1'
},
protocols: {
par: {
difficulty: '0x0f',
head: '0x02',
version: 63
}
}
}
]
})).to.deep.equal({
active: new BigNumber(789), active: new BigNumber(789),
connected: new BigNumber(456), connected: new BigNumber(456),
max: new BigNumber(123) max: new BigNumber(123),
peers: [
{
caps: ['par/1'],
id: '0x01',
name: 'Parity',
network: {
localAddress: '10.0.0.1',
remoteAddress: '10.0.0.1'
},
protocols: {
par: {
difficulty: new BigNumber(15),
head: '0x02',
version: 63
}
}
}
]
}); });
}); });
}); });

View File

@ -54,6 +54,11 @@ export default class Parity {
.execute('parity_checkRequest', inNumber16(requestId)); .execute('parity_checkRequest', inNumber16(requestId));
} }
consensusCapability () {
return this._transport
.execute('parity_consensusCapability');
}
dappsPort () { dappsPort () {
return this._transport return this._transport
.execute('parity_dappsPort') .execute('parity_dappsPort')
@ -90,6 +95,11 @@ export default class Parity {
.execute('parity_enode'); .execute('parity_enode');
} }
executeUpgrade () {
return this._transport
.execute('parity_executeUpgrade');
}
extraData () { extraData () {
return this._transport return this._transport
.execute('parity_extraData'); .execute('parity_extraData');
@ -243,6 +253,11 @@ export default class Parity {
.then(outAddress); .then(outAddress);
} }
releasesInfo () {
return this._transport
.execute('parity_releasesInfo');
}
removeReservedPeer (encode) { removeReservedPeer (encode) {
return this._transport return this._transport
.execute('parity_removeReservedPeer', encode); .execute('parity_removeReservedPeer', encode);
@ -315,4 +330,14 @@ export default class Parity {
.execute('parity_unsignedTransactionsCount') .execute('parity_unsignedTransactionsCount')
.then(outNumber); .then(outNumber);
} }
upgradeReady () {
return this._transport
.execute('parity_upgradeReady');
}
versionInfo () {
return this._transport
.execute('parity_versionInfo');
}
} }

View File

@ -80,7 +80,7 @@ describe('api/rpc/parity', () => {
describe('newPeers', () => { describe('newPeers', () => {
it('returns the peer structure, formatted', () => { it('returns the peer structure, formatted', () => {
mockHttp([{ method: 'parity_netPeers', reply: { result: { active: 123, connected: 456, max: 789 } } }]); mockHttp([{ method: 'parity_netPeers', reply: { result: { active: 123, connected: 456, max: 789, peers: [] } } }]);
return instance.netPeers().then((peers) => { return instance.netPeers().then((peers) => {
expect(peers.active.eq(123)).to.be.true; expect(peers.active.eq(123)).to.be.true;

View File

@ -1 +1 @@
[{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"reverse","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"},{"name":"_puzzle","type":"bytes32"},{"name":"_emailHash","type":"bytes32"}],"name":"puzzle","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_emailHash","type":"bytes32"}],"name":"request","outputs":[],"payable":true,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"uint256"}],"name":"setFee","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_code","type":"bytes32"}],"name":"confirm","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"drain","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"certified","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"fee","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"},{"indexed":false,"name":"emailHash","type":"bytes32"}],"name":"Requested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"},{"indexed":true,"name":"emailHash","type":"bytes32"},{"indexed":false,"name":"puzzle","type":"bytes32"}],"name":"Puzzled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Confirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Revoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"old","type":"address"},{"indexed":true,"name":"current","type":"address"}],"name":"NewOwner","type":"event"}] [{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"reverse","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"},{"name":"_puzzle","type":"bytes32"},{"name":"_emailHash","type":"bytes32"}],"name":"puzzle","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_emailHash","type":"bytes32"}],"name":"request","outputs":[],"payable":true,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"uint256"}],"name":"setFee","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_code","type":"bytes32"}],"name":"confirm","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"drain","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"certified","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"fee","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"},{"indexed":true,"name":"emailHash","type":"bytes32"}],"name":"Requested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"},{"indexed":true,"name":"emailHash","type":"bytes32"},{"indexed":false,"name":"puzzle","type":"bytes32"}],"name":"Puzzled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Confirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Revoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"old","type":"address"},{"indexed":true,"name":"current","type":"address"}],"name":"NewOwner","type":"event"}]

View File

@ -18,7 +18,8 @@ import { bytesToHex, hex2Ascii } from '~/api/util/format';
import ABI from './abi/certifier.json'; import ABI from './abi/certifier.json';
const ZERO = '0x0000000000000000000000000000000000000000000000000000000000000000'; const ZERO20 = '0x0000000000000000000000000000000000000000';
const ZERO32 = '0x0000000000000000000000000000000000000000000000000000000000000000';
export default class BadgeReg { export default class BadgeReg {
constructor (api, registry) { constructor (api, registry) {
@ -26,32 +27,57 @@ export default class BadgeReg {
this._registry = registry; this._registry = registry;
registry.getContract('badgereg'); registry.getContract('badgereg');
this.certifiers = {}; // by name this.certifiers = []; // by id
this.contracts = {}; // by name this.contracts = {}; // by name
} }
fetchCertifier (name) { certifierCount () {
if (this.certifiers[name]) { return this._registry.getContract('badgereg')
return Promise.resolve(this.certifiers[name]); .then((badgeReg) => {
return badgeReg.instance.badgeCount.call({}, [])
.then((count) => count.valueOf());
});
}
fetchCertifier (id) {
if (this.certifiers[id]) {
return Promise.resolve(this.certifiers[id]);
} }
return this._registry.getContract('badgereg') return this._registry.getContract('badgereg')
.then((badgeReg) => { .then((badgeReg) => {
return badgeReg.instance.fromName.call({}, [name]) return badgeReg.instance.badge.call({}, [ id ]);
.then(([ id, address ]) => { })
return Promise.all([ .then(([ address, name ]) => {
badgeReg.instance.meta.call({}, [id, 'TITLE']), if (address === ZERO20) {
badgeReg.instance.meta.call({}, [id, 'IMG']) throw new Error(`Certifier ${id} does not exist.`);
]) }
.then(([ title, img ]) => {
title = bytesToHex(title);
title = title === ZERO ? null : hex2Ascii(title);
if (bytesToHex(img) === ZERO) img = null;
const data = { address, name, title, icon: img }; name = bytesToHex(name);
this.certifiers[name] = data; name = name === ZERO32
return data; ? null
}); : hex2Ascii(name);
}); return this.fetchMeta(id)
.then(({ title, icon }) => {
const data = { address, id, name, title, icon };
this.certifiers[id] = data;
return data;
});
});
}
fetchMeta (id) {
return this._registry.getContract('badgereg')
.then((badgeReg) => {
return Promise.all([
badgeReg.instance.meta.call({}, [id, 'TITLE']),
badgeReg.instance.meta.call({}, [id, 'IMG'])
]);
})
.then(([ title, icon ]) => {
title = bytesToHex(title);
title = title === ZERO32 ? null : hex2Ascii(title);
if (bytesToHex(icon) === ZERO32) icon = null;
return { title, icon };
}); });
} }

View File

@ -100,6 +100,15 @@ export default {
} }
}, },
consensusCapability: {
desc: 'Returns an object or string detailing the state of parity capability of maintaining consensus',
params: [],
returns: {
type: Object,
desc: 'Either "capable", {"capableUntil":N}, {"incapableSince":N} or "unknown" (N is a block number)'
}
},
dappsPort: { dappsPort: {
desc: 'Returns the port the dapps are running on, error if not enabled', desc: 'Returns the port the dapps are running on, error if not enabled',
params: [], params: [],
@ -163,6 +172,15 @@ export default {
} }
}, },
executeUpgrade: {
desc: 'Performs an upgrade',
params: [],
returns: {
type: Boolean,
desc: 'returns true if the upgrade to the release specified in parity_upgradeReady was successfully executed, false if not'
}
},
extraData: { extraData: {
desc: 'Returns currently set extra data', desc: 'Returns currently set extra data',
params: [], params: [],
@ -468,6 +486,15 @@ export default {
} }
}, },
releasesInfo: {
desc: 'returns a ReleasesInfo object describing the current status of releases',
params: [],
returns: {
type: Object,
desc: '"fork":N,"minor":null,"this_fork":MN,"track":R} (N is a block number representing the latest known fork of this chain which may be in the future, MN is a block number representing the latest known fork that the currently running binary can sync past or null if not known, R is a ReleaseInfo object describing the latest release in this release track)'
}
},
removeReservedPeer: { removeReservedPeer: {
desc: '?', desc: '?',
params: [ params: [
@ -651,5 +678,23 @@ export default {
type: Quantity, type: Quantity,
desc: 'Number of unsigned transactions' desc: 'Number of unsigned transactions'
} }
},
upgradeReady: {
desc: 'returns a ReleaseInfo object describing the release which is available for upgrade or null if none is available',
params: [],
returns: {
type: Object,
desc: '{"binary":H,"fork":15100,"is_critical":true,"version":V} where H is the Keccak-256 checksum of the release parity binary and V is a VersionInfo object describing the release'
}
},
versionInfo: {
desc: 'returns a VersionInfo object describing our current version',
params: [],
returns: {
type: Object,
desc: '{"hash":H,"track":T,"version":{"major":N,"minor":N,"patch":N}} (H is a 160-bit Git commit hash, T is a ReleaseTrack, either "stable", "beta", "nightly" or "unknown" and N is a version number)'
}
} }
}; };

View File

@ -14,10 +14,4 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
import { ERRORS } from './newAccount';
export default from './newAccount'; export default from './newAccount';
export {
ERRORS
};

View File

@ -21,21 +21,10 @@ import ActionAutorenew from 'material-ui/svg-icons/action/autorenew';
import { Form, Input, IdentityIcon } from '~/ui'; import { Form, Input, IdentityIcon } from '~/ui';
import ERRORS from '../errors';
import styles from '../createAccount.css'; import styles from '../createAccount.css';
const ERRORS = {
noName: 'you need to specify a valid name for the account',
noPhrase: 'you need to specify the recovery phrase',
noKey: 'you need to provide the raw private key',
invalidKey: 'the raw key needs to be hex, 64 characters in length and contain the prefix "0x"',
invalidPassword: 'you need to specify a password >= 8 characters',
noMatchPassword: 'the supplied passwords does not match'
};
export {
ERRORS
};
export default class CreateAccount extends Component { export default class CreateAccount extends Component {
static contextTypes = { static contextTypes = {
api: PropTypes.object.isRequired, api: PropTypes.object.isRequired,
@ -49,15 +38,15 @@ export default class CreateAccount extends Component {
state = { state = {
accountName: '', accountName: '',
accountNameError: ERRORS.noName, accountNameError: ERRORS.noName,
accounts: null,
isValidName: false,
isValidPass: false,
passwordHint: '', passwordHint: '',
password1: '', password1: '',
password1Error: ERRORS.invalidPassword, password1Error: null,
password2: '', password2: '',
password2Error: ERRORS.noMatchPassword, password2Error: null,
accounts: null, selectedAddress: ''
selectedAddress: '',
isValidPass: false,
isValidName: false
} }
componentWillMount () { componentWillMount () {
@ -230,60 +219,55 @@ export default class CreateAccount extends Component {
}, this.updateParent); }, this.updateParent);
} }
onEditPasswordHint = (event, value) => { onEditPasswordHint = (event, passwordHint) => {
this.setState({ this.setState({
passwordHint: value passwordHint
}); });
} }
onEditAccountName = (event) => { onEditAccountName = (event) => {
const value = event.target.value; const accountName = event.target.value;
let error = null; let accountNameError = null;
if (!value || value.trim().length < 2) { if (!accountName || !accountName.trim().length) {
error = ERRORS.noName; accountNameError = ERRORS.noName;
} }
this.setState({ this.setState({
accountName: value, accountName,
accountNameError: error, accountNameError,
isValidName: !error isValidName: !accountNameError
}, this.updateParent); }, this.updateParent);
} }
onEditPassword1 = (event) => { onEditPassword1 = (event) => {
const value = event.target.value; const password1 = event.target.value;
let error1 = null; let password2Error = null;
let error2 = null;
if (!value || value.trim().length < 8) { if (password1 !== this.state.password2) {
error1 = ERRORS.invalidPassword; password2Error = ERRORS.noMatchPassword;
}
if (value !== this.state.password2) {
error2 = ERRORS.noMatchPassword;
} }
this.setState({ this.setState({
password1: value, password1,
password1Error: error1, password1Error: null,
password2Error: error2, password2Error,
isValidPass: !error1 && !error2 isValidPass: !password2Error
}, this.updateParent); }, this.updateParent);
} }
onEditPassword2 = (event) => { onEditPassword2 = (event) => {
const value = event.target.value; const password2 = event.target.value;
let error2 = null; let password2Error = null;
if (value !== this.state.password1) { if (password2 !== this.state.password1) {
error2 = ERRORS.noMatchPassword; password2Error = ERRORS.noMatchPassword;
} }
this.setState({ this.setState({
password2: value, password2,
password2Error: error2, password2Error,
isValidPass: !error2 isValidPass: !password2Error
}, this.updateParent); }, this.updateParent);
} }

View File

@ -47,6 +47,7 @@ export default class NewGeth extends Component {
<div className={ styles.list }>There are currently no importable keys available from the Geth keystore, which are not already available on your Parity instance</div> <div className={ styles.list }>There are currently no importable keys available from the Geth keystore, which are not already available on your Parity instance</div>
); );
} }
const checkboxes = available.map((account) => { const checkboxes = available.map((account) => {
const label = ( const label = (
<div className={ styles.selection }> <div className={ styles.selection }>

View File

@ -21,17 +21,13 @@ import EditorAttachFile from 'material-ui/svg-icons/editor/attach-file';
import { Form, Input } from '~/ui'; import { Form, Input } from '~/ui';
import ERRORS from '../errors';
import styles from '../createAccount.css'; import styles from '../createAccount.css';
const FAKEPATH = 'C:\\fakepath\\'; const FAKEPATH = 'C:\\fakepath\\';
const STYLE_HIDDEN = { display: 'none' }; const STYLE_HIDDEN = { display: 'none' };
const ERRORS = {
noName: 'you need to specify a valid name for the account',
noPassword: 'supply a valid password to confirm the transaction',
noFile: 'select a valid wallet file to import'
};
export default class NewImport extends Component { export default class NewImport extends Component {
static propTypes = { static propTypes = {
onChange: PropTypes.func.isRequired onChange: PropTypes.func.isRequired
@ -40,15 +36,15 @@ export default class NewImport extends Component {
state = { state = {
accountName: '', accountName: '',
accountNameError: ERRORS.noName, accountNameError: ERRORS.noName,
passwordHint: '', isValidFile: false,
password: '',
passwordError: ERRORS.noPassword,
walletFile: '',
walletFileError: ERRORS.noFile,
walletJson: '',
isValidPass: false, isValidPass: false,
isValidName: false, isValidName: false,
isValidFile: false password: '',
passwordError: null,
passwordHint: '',
walletFile: '',
walletFileError: ERRORS.noFile,
walletJson: ''
} }
componentWillMount () { componentWillMount () {
@ -143,39 +139,34 @@ export default class NewImport extends Component {
}); });
} }
onEditPasswordHint = (event, value) => { onEditPasswordHint = (event, passwordHint) => {
this.setState({ this.setState({
passwordHint: value passwordHint
}); });
} }
onEditAccountName = (event) => { onEditAccountName = (event) => {
const value = event.target.value; const accountName = event.target.value;
let error = null; let accountNameError = null;
if (!value || value.trim().length < 2) { if (!accountName || !accountName.trim().length) {
error = ERRORS.noName; accountNameError = ERRORS.noName;
} }
this.setState({ this.setState({
accountName: value, accountName,
accountNameError: error, accountNameError,
isValidName: !error isValidName: !accountNameError
}, this.updateParent); }, this.updateParent);
} }
onEditPassword = (event) => { onEditPassword = (event) => {
let error = null; const password = event.target.value;
const value = event.target.value;
if (!value || !value.length) {
error = ERRORS.noPassword;
}
this.setState({ this.setState({
password: value, password,
passwordError: error, passwordError: null,
isValidPass: !error isValidPass: true
}, this.updateParent); }, this.updateParent);
} }
} }

View File

@ -20,7 +20,7 @@ import { Form, Input } from '~/ui';
import styles from '../createAccount.css'; import styles from '../createAccount.css';
import { ERRORS } from '../NewAccount'; import ERRORS from '../errors';
export default class RawKey extends Component { export default class RawKey extends Component {
static contextTypes = { static contextTypes = {
@ -32,18 +32,18 @@ export default class RawKey extends Component {
} }
state = { state = {
rawKey: '',
rawKeyError: ERRORS.noKey,
accountName: '', accountName: '',
accountNameError: ERRORS.noName, accountNameError: ERRORS.noName,
isValidKey: false,
isValidName: false,
isValidPass: false,
passwordHint: '', passwordHint: '',
password1: '', password1: '',
password1Error: ERRORS.invalidPassword, password1Error: null,
password2: '', password2: '',
password2Error: ERRORS.noMatchPassword, password2Error: null,
isValidPass: false, rawKey: '',
isValidName: false, rawKeyError: ERRORS.noKey
isValidKey: false
} }
componentWillMount () { componentWillMount () {
@ -138,7 +138,7 @@ export default class RawKey extends Component {
const accountName = event.target.value; const accountName = event.target.value;
let accountNameError = null; let accountNameError = null;
if (!accountName || accountName.trim().length < 2) { if (!accountName || !accountName.trim().length) {
accountNameError = ERRORS.noName; accountNameError = ERRORS.noName;
} }
@ -150,38 +150,33 @@ export default class RawKey extends Component {
} }
onEditPassword1 = (event) => { onEditPassword1 = (event) => {
const value = event.target.value; const password1 = event.target.value;
let error1 = null; let password2Error = null;
let error2 = null;
if (!value || value.trim().length < 8) { if (password1 !== this.state.password2) {
error1 = ERRORS.invalidPassword; password2Error = ERRORS.noMatchPassword;
}
if (value !== this.state.password2) {
error2 = ERRORS.noMatchPassword;
} }
this.setState({ this.setState({
password1: value, password1,
password1Error: error1, password1Error: null,
password2Error: error2, password2Error,
isValidPass: !error1 && !error2 isValidPass: !password2Error
}, this.updateParent); }, this.updateParent);
} }
onEditPassword2 = (event) => { onEditPassword2 = (event) => {
const value = event.target.value; const password2 = event.target.value;
let error2 = null; let password2Error = null;
if (value !== this.state.password1) { if (password2 !== this.state.password1) {
error2 = ERRORS.noMatchPassword; password2Error = ERRORS.noMatchPassword;
} }
this.setState({ this.setState({
password2: value, password2,
password2Error: error2, password2Error,
isValidPass: !error2 isValidPass: !password2Error
}, this.updateParent); }, this.updateParent);
} }
} }

View File

@ -21,7 +21,7 @@ import { Form, Input } from '~/ui';
import styles from '../createAccount.css'; import styles from '../createAccount.css';
import { ERRORS } from '../NewAccount'; import ERRORS from '../errors';
export default class RecoveryPhrase extends Component { export default class RecoveryPhrase extends Component {
static propTypes = { static propTypes = {
@ -29,19 +29,19 @@ export default class RecoveryPhrase extends Component {
} }
state = { state = {
recoveryPhrase: '',
recoveryPhraseError: ERRORS.noPhrase,
accountName: '', accountName: '',
accountNameError: ERRORS.noName, accountNameError: ERRORS.noName,
passwordHint: '',
password1: '',
password1Error: ERRORS.invalidPassword,
password2: '',
password2Error: ERRORS.noMatchPassword,
windowsPhrase: false,
isValidPass: false, isValidPass: false,
isValidName: false, isValidName: false,
isValidPhrase: false isValidPhrase: false,
passwordHint: '',
password1: '',
password1Error: null,
password2: '',
password2Error: null,
recoveryPhrase: '',
recoveryPhraseError: null,
windowsPhrase: false
} }
componentWillMount () { componentWillMount () {
@ -99,13 +99,13 @@ export default class RecoveryPhrase extends Component {
} }
updateParent = () => { updateParent = () => {
const { isValidName, isValidPass, isValidPhrase, accountName, passwordHint, password1, recoveryPhrase, windowsPhrase } = this.state; const { accountName, isValidName, isValidPass, isValidPhrase, password1, passwordHint, recoveryPhrase, windowsPhrase } = this.state;
const isValid = isValidName && isValidPass && isValidPhrase; const isValid = isValidName && isValidPass && isValidPhrase;
this.props.onChange(isValid, { this.props.onChange(isValid, {
name: accountName, name: accountName,
passwordHint,
password: password1, password: password1,
passwordHint,
phrase: recoveryPhrase, phrase: recoveryPhrase,
windowsPhrase windowsPhrase
}); });
@ -134,67 +134,57 @@ export default class RecoveryPhrase extends Component {
.split(' ') .split(' ')
.map((part) => part.trim()) .map((part) => part.trim())
.filter((part) => part.length); .filter((part) => part.length);
let recoveryPhraseError = null;
if (!recoveryPhrase || recoveryPhrase.length < 25 || phraseParts.length < 8) {
recoveryPhraseError = ERRORS.noPhrase;
}
this.setState({ this.setState({
recoveryPhrase: phraseParts.join(' '), recoveryPhrase: phraseParts.join(' '),
recoveryPhraseError, recoveryPhraseError: null,
isValidPhrase: !recoveryPhraseError isValidPhrase: true
}, this.updateParent); }, this.updateParent);
} }
onEditAccountName = (event) => { onEditAccountName = (event) => {
const value = event.target.value; const accountName = event.target.value;
let error = null; let accountNameError = null;
if (!value || value.trim().length < 2) { if (!accountName || !accountName.trim().length) {
error = ERRORS.noName; accountNameError = ERRORS.noName;
} }
this.setState({ this.setState({
accountName: value, accountName,
accountNameError: error, accountNameError,
isValidName: !error isValidName: !accountNameError
}, this.updateParent); }, this.updateParent);
} }
onEditPassword1 = (event) => { onEditPassword1 = (event) => {
const value = event.target.value; const password1 = event.target.value;
let error1 = null; let password2Error = null;
let error2 = null;
if (!value || value.trim().length < 8) { if (password1 !== this.state.password2) {
error1 = ERRORS.invalidPassword; password2Error = ERRORS.noMatchPassword;
}
if (value !== this.state.password2) {
error2 = ERRORS.noMatchPassword;
} }
this.setState({ this.setState({
password1: value, password1,
password1Error: error1, password1Error: null,
password2Error: error2, password2Error,
isValidPass: !error1 && !error2 isValidPass: !password2Error
}, this.updateParent); }, this.updateParent);
} }
onEditPassword2 = (event) => { onEditPassword2 = (event) => {
const value = event.target.value; const password2 = event.target.value;
let error2 = null; let password2Error = null;
if (value !== this.state.password1) { if (password2 !== this.state.password1) {
error2 = ERRORS.noMatchPassword; password2Error = ERRORS.noMatchPassword;
} }
this.setState({ this.setState({
password2: value, password2,
password2Error: error2, password2Error,
isValidPass: !error2 isValidPass: !password2Error
}, this.updateParent); }, this.updateParent);
} }
} }

View File

@ -15,6 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl';
import ActionDone from 'material-ui/svg-icons/action/done'; import ActionDone from 'material-ui/svg-icons/action/done';
import ActionDoneAll from 'material-ui/svg-icons/action/done-all'; import ActionDoneAll from 'material-ui/svg-icons/action/done-all';
import ContentClear from 'material-ui/svg-icons/content/clear'; import ContentClear from 'material-ui/svg-icons/content/clear';
@ -22,7 +23,7 @@ import NavigationArrowBack from 'material-ui/svg-icons/navigation/arrow-back';
import NavigationArrowForward from 'material-ui/svg-icons/navigation/arrow-forward'; import NavigationArrowForward from 'material-ui/svg-icons/navigation/arrow-forward';
import PrintIcon from 'material-ui/svg-icons/action/print'; import PrintIcon from 'material-ui/svg-icons/action/print';
import { Button, Modal } from '~/ui'; import { Button, Modal, Warning } from '~/ui';
import AccountDetails from './AccountDetails'; import AccountDetails from './AccountDetails';
import AccountDetailsGeth from './AccountDetailsGeth'; import AccountDetailsGeth from './AccountDetailsGeth';
@ -86,6 +87,7 @@ export default class CreateAccount extends Component {
actions={ this.renderDialogActions() } actions={ this.renderDialogActions() }
current={ stage } current={ stage }
steps={ steps }> steps={ steps }>
{ this.renderWarning() }
{ this.renderPage() } { this.renderPage() }
</Modal> </Modal>
); );
@ -200,6 +202,22 @@ export default class CreateAccount extends Component {
} }
} }
renderWarning () {
const { createType, stage } = this.state;
if (stage !== 1 || ['fromJSON', 'fromPresale'].includes(createType)) {
return null;
}
return (
<Warning warning={
<FormattedMessage
id='createAccount.warning.insecurePassword'
defaultMessage='It is recommended that a strong password be used to secure your accounts. Empty and trivial passwords are a security risk.' />
} />
);
}
onNext = () => { onNext = () => {
this.setState({ this.setState({
stage: this.state.stage + 1 stage: this.state.stage + 1

View File

@ -0,0 +1,45 @@
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React from 'react';
import { FormattedMessage } from 'react-intl';
export default {
noFile:
<FormattedMessage
id='createAccount.error.noFile'
defaultMessage='select a valid wallet file to import' />,
noKey:
<FormattedMessage
id='createAccount.error.noKey'
defaultMessage='you need to provide the raw private key' />,
noMatchPassword:
<FormattedMessage
id='createAccount.error.noMatchPassword'
defaultMessage='the supplied passwords does not match' />,
noName:
<FormattedMessage
id='createAccount.error.noName'
defaultMessage='you need to specify a valid name for the account' />,
invalidKey:
<FormattedMessage
id='createAccount.error.invalidKey'
defaultMessage='the raw key needs to be hex, 64 characters in length and contain the prefix "0x"' />
};

View File

@ -17,7 +17,6 @@
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { Form, TypedInput, Input, AddressSelect, InputAddress } from '~/ui'; import { Form, TypedInput, Input, AddressSelect, InputAddress } from '~/ui';
import { parseAbiType } from '~/util/abi';
import styles from '../createWallet.css'; import styles from '../createWallet.css';
@ -105,7 +104,7 @@ export default class WalletDetails extends Component {
value={ wallet.owners.slice() } value={ wallet.owners.slice() }
onChange={ this.onOwnersChange } onChange={ this.onOwnersChange }
accounts={ accounts } accounts={ accounts }
param={ parseAbiType('address[]') } param='address[]'
/> />
<div className={ styles.splitInput }> <div className={ styles.splitInput }>
@ -115,7 +114,7 @@ export default class WalletDetails extends Component {
value={ wallet.required } value={ wallet.required }
error={ errors.required } error={ errors.required }
onChange={ this.onRequiredChange } onChange={ this.onRequiredChange }
param={ parseAbiType('uint') } param='uint'
min={ 1 } min={ 1 }
max={ wallet.owners.length + 1 } max={ wallet.owners.length + 1 }
/> />
@ -126,7 +125,7 @@ export default class WalletDetails extends Component {
value={ wallet.daylimit } value={ wallet.daylimit }
error={ errors.daylimit } error={ errors.daylimit }
onChange={ this.onDaylimitChange } onChange={ this.onDaylimitChange }
param={ parseAbiType('uint') } param='uint'
isEth isEth
/> />
</div> </div>

View File

@ -83,6 +83,7 @@ export default class ParametersStep extends Component {
accounts={ accounts } accounts={ accounts }
onChange={ onChange } onChange={ onChange }
param={ param } param={ param }
isEth={ false }
/> />
</div> </div>
); );

View File

@ -18,7 +18,6 @@ import React, { Component, PropTypes } from 'react';
import { Checkbox, MenuItem } from 'material-ui'; import { Checkbox, MenuItem } from 'material-ui';
import { AddressSelect, Form, Input, Select, TypedInput } from '~/ui'; import { AddressSelect, Form, Input, Select, TypedInput } from '~/ui';
import { parseAbiType } from '~/util/abi';
import styles from '../executeContract.css'; import styles from '../executeContract.css';
@ -162,7 +161,8 @@ export default class DetailsStep extends Component {
error={ valuesError[index] } error={ valuesError[index] }
onChange={ onChange } onChange={ onChange }
accounts={ accounts } accounts={ accounts }
param={ parseAbiType(input.type) } param={ input.type }
isEth={ false }
/> />
</div> </div>
); );

View File

@ -15,6 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import ActionDone from 'material-ui/svg-icons/action/done'; import ActionDone from 'material-ui/svg-icons/action/done';
import ActionDoneAll from 'material-ui/svg-icons/action/done-all'; import ActionDoneAll from 'material-ui/svg-icons/action/done-all';
import NavigationArrowForward from 'material-ui/svg-icons/navigation/arrow-forward'; import NavigationArrowForward from 'material-ui/svg-icons/navigation/arrow-forward';
@ -35,14 +36,15 @@ import ParityLogo from '../../../assets/images/parity-logo-black-no-text.svg';
const STAGE_NAMES = ['welcome', 'terms', 'new account', 'recovery', 'completed']; const STAGE_NAMES = ['welcome', 'terms', 'new account', 'recovery', 'completed'];
export default class FirstRun extends Component { class FirstRun extends Component {
static contextTypes = { static contextTypes = {
api: PropTypes.object.isRequired, api: PropTypes.object.isRequired,
store: PropTypes.object.isRequired store: PropTypes.object.isRequired
} }
static propTypes = { static propTypes = {
visible: PropTypes.bool, hasAccounts: PropTypes.bool.isRequired,
visible: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired onClose: PropTypes.func.isRequired
} }
@ -109,6 +111,7 @@ export default class FirstRun extends Component {
} }
renderDialogActions () { renderDialogActions () {
const { hasAccounts } = this.props;
const { canCreate, stage, hasAcceptedTnc } = this.state; const { canCreate, stage, hasAcceptedTnc } = this.state;
switch (stage) { switch (stage) {
@ -130,13 +133,26 @@ export default class FirstRun extends Component {
); );
case 2: case 2:
return ( const buttons = [
<Button <Button
icon={ <ActionDone /> } icon={ <ActionDone /> }
label='Create' label='Create'
key='create'
disabled={ !canCreate } disabled={ !canCreate }
onClick={ this.onCreate } /> onClick={ this.onCreate }
); />
];
if (hasAccounts) {
buttons.unshift(
<Button
icon={ <NavigationArrowForward /> }
label='Skip'
key='skip'
onClick={ this.skipAccountCreation }
/>
);
}
return buttons;
case 3: case 3:
return [ return [
@ -219,6 +235,10 @@ export default class FirstRun extends Component {
}); });
} }
skipAccountCreation = () => {
this.setState({ stage: this.state.stage + 2 });
}
newError = (error) => { newError = (error) => {
const { store } = this.context; const { store } = this.context;
@ -232,3 +252,9 @@ export default class FirstRun extends Component {
print(recoveryPage({ phrase, name, identity, address, logo: ParityLogo })); print(recoveryPage({ phrase, name, identity, address, logo: ParityLogo }));
} }
} }
function mapStateToProps (state) {
return { hasAccounts: state.personal.hasAccounts };
}
export default connect(mapStateToProps, null)(FirstRun);

View File

@ -0,0 +1,17 @@
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './upgradeParity';

View File

@ -0,0 +1,146 @@
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import { action, computed, observable, transaction } from 'mobx';
import store from 'store';
const LS_UPDATE = '_parity::update';
const A_MINUTE = 60 * 1000;
const A_DAY = 24 * 60 * A_MINUTE;
const STEP_INFO = 0;
const STEP_UPDATING = 1;
const STEP_COMPLETED = 2;
const STEP_ERROR = 2;
const CHECK_INTERVAL = 1 * A_MINUTE;
export default class Store {
@observable available = null;
@observable consensusCapability = null;
@observable closed = true;
@observable error = null;
@observable remindAt = 0;
@observable step = 0;
@observable upgrading = null;
@observable version = null;
constructor (api) {
this._api = api;
this.loadStorage();
this.checkUpgrade();
setInterval(this.checkUpgrade, CHECK_INTERVAL);
}
@computed get isVisible () {
return !this.closed && Date.now() >= this.remindAt;
}
@action closeModal = () => {
transaction(() => {
this.closed = true;
this.setStep(0, null);
});
}
@action loadStorage = () => {
const values = store.get(LS_UPDATE) || {};
this.remindAt = values.remindAt ? values.remindAt : 0;
return values;
}
@action openModal = () => {
this.closed = false;
}
@action setStep = (step, error = null) => {
transaction(() => {
this.error = error;
this.step = step;
});
}
@action setUpgrading () {
transaction(() => {
this.upgrading = this.available;
this.setStep(STEP_UPDATING, null);
});
}
@action setVersions (available, version, consensusCapability) {
transaction(() => {
this.available = available;
this.consensusCapability = consensusCapability;
this.version = version;
});
}
@action snoozeTillTomorrow = () => {
this.remindAt = Date.now() + A_DAY;
store.set(LS_UPDATE, Object.assign(this.loadStorage(), { remindAt: this.remindAt }));
}
@action upgradeNow = () => {
this.setUpgrading();
return this._api.parity
.executeUpgrade()
.then((result) => {
if (!result) {
throw new Error('Unable to complete update');
}
this.setStep(STEP_COMPLETED, null);
})
.catch((error) => {
console.error('upgradeNow', error);
this.setStep(STEP_ERROR, error);
});
}
checkUpgrade = () => {
if (!this._api) {
return;
}
Promise
.all([
this._api.parity.upgradeReady(),
this._api.parity.consensusCapability(),
this._api.parity.versionInfo()
])
.then(([available, consensusCapability, version]) => {
console.log('[checkUpgrade]', 'available:', available, 'version:', version, 'consensusCapability:', consensusCapability);
this.setVersions(available, version, consensusCapability);
})
.catch((error) => {
console.warn('checkUpgrade', error);
});
}
}
export {
STEP_COMPLETED,
STEP_ERROR,
STEP_INFO,
STEP_UPDATING
};

Some files were not shown because too many files have changed in this diff Show More