Merge pull request #3505 from ethcore/check-updates

Auto-updating
This commit is contained in:
Gav Wood 2016-12-16 13:01:49 +01:00 committed by GitHub
commit 6e5a583cb4
108 changed files with 3766 additions and 470 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:
- curl --data "secret=$RELEASES_SECRET" http://icarus.parity.io/push-release/$CI_BUILD_REF_NAME/$CI_BUILD_REF
- cargo build -j $(nproc) --release $CARGOFLAGS - cargo build -j $(nproc) --release $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/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"
- export PLATFORM=x86_64-unknown-centos-gnu
- cargo build -j $(nproc) --release $CARGOFLAGS - cargo build -j $(nproc) --release $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/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++
- export COMMIT=$(git rev-parse HEAD)
- export PLATFORM=i686-unknown-linux-gnu
- cargo build -j $(nproc) --target i686-unknown-linux-gnu --release $CARGOFLAGS - cargo build -j $(nproc) --target i686-unknown-linux-gnu --release $CARGOFLAGS
- strip target/i686-unknown-linux-gnu/release/parity - strip target/$PLATFORM/release/parity
- md5sum target/i686-unknown-linux-gnu/release/parity > parity.md5 - 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/push-build/$CI_BUILD_REF_NAME/$PLATFORM
tags: tags:
- rust - rust
- rust-i686 - rust-i686
@ -292,7 +302,6 @@ linux-aarch64:
- 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/aarch64-unknown-linux-gnu
- 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/aarch64-unknown-linux-gnu/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/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/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/aarch64-unknown-linux-gnu/"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"
@ -312,10 +321,13 @@ darwin:
- stable - stable
- triggers - triggers
script: script:
- export COMMIT=$(git rev-parse HEAD)
- export PLATFORM=x86_64-apple-darwin
- cargo build -j 8 --release #$CARGOFLAGS - cargo build -j 8 --release #$CARGOFLAGS
- cargo build -j 8 --release -p ethstore #$CARGOFLAGS - cargo build -j 8 --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 +335,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/push-build/$CI_BUILD_REF_NAME/$PLATFORM
tags: tags:
- osx - osx
artifacts: artifacts:
@ -345,12 +358,14 @@ 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 --release #%CARGOFLAGS%
- FOR /F "tokens=* USEBACKQ" %%i IN ('target\release\parity.exe tools hash target\release\parity.exe') DO set SHA3=%%i
- 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 - signtool sign /f %keyfile% /p %certpass% target\release\parity.exe
@ -385,6 +400,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/push-build/$CI_BUILD_REF_NAME/%PLATFORM%
tags: tags:
- rust-windows - rust-windows
artifacts: artifacts:
@ -399,9 +415,10 @@ 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
@ -413,7 +430,7 @@ test-windows:
- 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 +465,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 +480,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

92
Cargo.lock generated
View File

@ -12,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",
@ -33,14 +32,16 @@ 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-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", "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)",
@ -306,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",
@ -330,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)",
] ]
@ -359,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",
@ -371,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)",
@ -390,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"
@ -420,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]]
@ -443,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)",
] ]
@ -468,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]]
@ -546,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)",
@ -589,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]]
@ -705,7 +697,7 @@ dependencies = [
"parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
] ]
@ -794,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)",
@ -860,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"
@ -1324,6 +1328,18 @@ 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]] [[package]]
name = "parity-rpc-client" name = "parity-rpc-client"
version = "1.4.0" version = "1.4.0"
@ -1368,6 +1384,21 @@ 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",
]
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.2.8" version = "0.2.8"
@ -1697,6 +1728,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"
@ -2265,6 +2313,8 @@ dependencies = [
"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"

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"
@ -32,25 +32,26 @@ 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" } rpc-cli = { path = "rpc_cli" }
parity-rpc-client = { path = "rpc_client" } parity-rpc-client = { path = "rpc_client" }
ethcore-light = { path = "ethcore/light" } ethcore-light = { path = "ethcore/light" }
parity-hash-fetch = { path = "hash-fetch" }
parity-updater = { path = "updater" }
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
winapi = "0.2" winapi = "0.2"

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

@ -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

@ -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

@ -15,7 +15,8 @@
"eip155Transition": 10, "eip155Transition": 10,
"eip160Transition": 10, "eip160Transition": 10,
"eip161abcTransition": 10, "eip161abcTransition": 10,
"eip161dTransition": 10 "eip161dTransition": 10,
"maxCodeSize": 24576
} }
} }
}, },

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, 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))
@ -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

@ -488,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);
@ -694,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

@ -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>;
@ -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

@ -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

@ -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

@ -34,4 +34,5 @@ pub mod block_import_error;
pub mod restoration_status; 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

@ -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

@ -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",

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

@ -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

@ -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
};

View File

@ -0,0 +1,58 @@
// 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 Store from './store';
let store;
describe('modals/UpgradeParity/store', () => {
describe('@actions', () => {
beforeEach(() => {
store = new Store();
});
describe('openModal & closeModal', () => {
it('toggles between the closed states', () => {
expect(store.closed).to.be.true;
store.openModal();
expect(store.closed).to.be.false;
store.closeModal();
expect(store.closed).to.be.true;
});
it('resets the step state upon closing', () => {
store.setStep(5, 'soem error');
store.closeModal();
expect(store.step).to.equal(0);
expect(store.error).to.be.null;
});
});
describe('setStep', () => {
it('sets the step as provided', () => {
expect(store.step).to.equal(0);
store.setStep(3);
expect(store.step).to.equal(3);
});
it('sets the error when provided', () => {
expect(store.error).to.be.null;
store.setStep(3, new Error('some error'));
expect(store.error).to.match(/some error/);
});
});
});
});

View File

@ -0,0 +1,32 @@
/* 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/>.
*/
.error {
padding-top: 1.25em;
}
.infoStep {
div+div {
padding-top: 1.25em;
}
}
.version {
display: inline;
opacity: 0.5;
white-space: normal;
}

View File

@ -0,0 +1,257 @@
// 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 { observer } from 'mobx-react';
import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl';
import { Button } from '~/ui';
import { CancelIcon, DoneIcon, NextIcon } from '~/ui/Icons';
import Modal, { Busy, Completed } from '~/ui/Modal';
import { STEP_COMPLETED, STEP_ERROR, STEP_INFO, STEP_UPDATING } from './store';
import styles from './upgradeParity.css';
@observer
export default class UpgradeParity extends Component {
static contextTypes = {
api: PropTypes.object.isRequired
};
static propTypes = {
store: PropTypes.object.isRequired
}
render () {
const { store } = this.props;
if (!store.isVisible) {
return null;
}
return (
<Modal
actions={ this.renderActions() }
current={ store.step }
steps={ [
<FormattedMessage
id='upgradeParity.step.info'
key='info'
defaultMessage='upgrade available' />,
<FormattedMessage
key='updating'
id='upgradeParity.step.updating'
defaultMessage='upgrading parity' />,
store.step === STEP_ERROR
? <FormattedMessage
id='upgradeParity.step.error'
key='error'
defaultMessage='error' />
: <FormattedMessage
id='upgradeParity.step.completed'
key='completed'
defaultMessage='upgrade completed' />
] }
visible>
{ this.renderStep() }
</Modal>
);
}
renderActions () {
const { store } = this.props;
const closeButton =
<Button
icon={ <CancelIcon /> }
key='close'
label={
<FormattedMessage
id='upgradeParity.button.close'
defaultMessage='close' />
}
onClick={ store.closeModal } />;
const doneButton =
<Button
icon={ <DoneIcon /> }
key='done'
label={
<FormattedMessage
id='upgradeParity.button.done'
defaultMessage='done' />
}
onClick={ store.closeModal } />;
switch (store.step) {
case STEP_INFO:
return [
<Button
icon={ <NextIcon /> }
key='upgrade'
label={
<FormattedMessage
id='upgradeParity.button.upgrade'
defaultMessage='upgrade now' />
}
onClick={ store.upgradeNow } />,
closeButton
];
case STEP_UPDATING:
return [
closeButton
];
case STEP_COMPLETED:
case STEP_ERROR:
return [
doneButton
];
}
}
renderStep () {
const { store } = this.props;
const currentversion = this.formatVersion(store);
const newversion = store.upgrading
? this.formatVersion(store.upgrading)
: this.formatVersion(store.available);
switch (store.step) {
case STEP_INFO:
return (
<div className={ styles.infoStep }>
<div>
<FormattedMessage
id='upgradeParity.info.upgrade'
defaultMessage='A new version of Parity, version {newversion} is available as an upgrade from your current version {currentversion}'
values={ {
currentversion: <div className={ styles.version }>{ currentversion }</div>,
newversion: <div className={ styles.version }>{ newversion }</div>
} } />
</div>
{ this.renderConsensusInfo() }
</div>
);
case STEP_UPDATING:
return (
<Busy
title={
<FormattedMessage
id='upgradeParity.busy'
defaultMessage='Your upgrade to Parity {newversion} is currently in progress'
values={ {
newversion: <div className={ styles.version }>{ newversion }</div>
} } />
} />
);
case STEP_COMPLETED:
case STEP_ERROR:
if (store.error) {
return (
<Completed>
<div>
<FormattedMessage
id='upgradeParity.failed'
defaultMessage='Your upgrade to Parity {newversion} has failed with an error.'
values={ {
newversion: <div className={ styles.version }>{ newversion }</div>
} } />
</div>
<div className={ styles.error }>
{ store.error.message }
</div>
</Completed>
);
}
return (
<Completed>
<FormattedMessage
id='upgradeParity.completed'
defaultMessage='Your upgrade to Parity {newversion} has been successfully completed.'
values={ {
newversion: <div className={ styles.version }>{ newversion }</div>
} } />
</Completed>
);
}
}
renderConsensusInfo () {
const { store } = this.props;
const { consensusCapability } = store;
if (consensusCapability) {
if (consensusCapability === 'capable') {
return (
<div>
<FormattedMessage
id='upgradeParity.consensus.capable'
defaultMessage='Your current Parity version is capable of handling the network requirements.' />
</div>
);
} else if (consensusCapability.capableUntil) {
return (
<div>
<FormattedMessage
id='upgradeParity.consensus.capableUntil'
defaultMessage='Your current Parity version is capable of handling the network requirements until block {blockNumber}'
values={ {
blockNumber: consensusCapability.capableUntil
} } />
</div>
);
} else if (consensusCapability.incapableSince) {
return (
<div>
<FormattedMessage
id='upgradeParity.consensus.incapableSince'
defaultMessage='Your current Parity version is incapable of handling the network requirements since block {blockNumber}'
values={ {
blockNumber: consensusCapability.incapableSince
} } />
</div>
);
}
}
return (
<div>
<FormattedMessage
id='upgradeParity.consensus.unknown'
defaultMessage='Your current Parity version is capable of handling the network requirements.' />
</div>
);
}
formatVersion (struct) {
if (!struct || !struct.version) {
return (
<FormattedMessage
id='upgradeParity.version.unknown'
defaultMessage='unknown' />
);
}
const { track, version } = struct.version;
return `${version.major}.${version.minor}.${version.patch}-${track}`;
}
}

View File

@ -23,12 +23,13 @@ import DeployContract from './DeployContract';
import EditMeta from './EditMeta'; import EditMeta from './EditMeta';
import ExecuteContract from './ExecuteContract'; import ExecuteContract from './ExecuteContract';
import FirstRun from './FirstRun'; import FirstRun from './FirstRun';
import LoadContract from './LoadContract';
import SaveContract from './SaveContract';
import Shapeshift from './Shapeshift'; import Shapeshift from './Shapeshift';
import Verification from './Verification'; import Verification from './Verification';
import Transfer from './Transfer'; import Transfer from './Transfer';
import PasswordManager from './PasswordManager'; import PasswordManager from './PasswordManager';
import SaveContract from './SaveContract'; import UpgradeParity from './UpgradeParity';
import LoadContract from './LoadContract';
import WalletSettings from './WalletSettings'; import WalletSettings from './WalletSettings';
export { export {
@ -41,11 +42,12 @@ export {
EditMeta, EditMeta,
ExecuteContract, ExecuteContract,
FirstRun, FirstRun,
LoadContract,
SaveContract,
Shapeshift, Shapeshift,
Verification, Verification,
Transfer, Transfer,
PasswordManager, PasswordManager,
LoadContract, UpgradeParity,
SaveContract,
WalletSettings WalletSettings
}; };

31
js/src/ui/Icons/index.js Normal file
View File

@ -0,0 +1,31 @@
// 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 AddIcon from 'material-ui/svg-icons/content/add';
import CancelIcon from 'material-ui/svg-icons/content/clear';
import DoneIcon from 'material-ui/svg-icons/action/done-all';
import PrevIcon from 'material-ui/svg-icons/navigation/arrow-back';
import NextIcon from 'material-ui/svg-icons/navigation/arrow-forward';
import SnoozeIcon from 'material-ui/svg-icons/av/snooze';
export {
AddIcon,
CancelIcon,
DoneIcon,
PrevIcon,
NextIcon,
SnoozeIcon
};

View File

@ -16,17 +16,19 @@
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { nodeOrStringProptype } from '~/util/proptypes';
import styles from './busy.css'; import styles from './busy.css';
export default class Busy extends Component { export default class Busy extends Component {
static propTypes = { static propTypes = {
title: PropTypes.string, children: PropTypes.node,
state: PropTypes.string, state: nodeOrStringProptype(),
children: PropTypes.node title: nodeOrStringProptype()
} }
render () { render () {
const { children, title, state } = this.props; const { children, state, title } = this.props;
return ( return (
<div className={ styles.center }> <div className={ styles.center }>

View File

@ -36,7 +36,13 @@ export default class Title extends Component {
return ( return (
<div className={ styles.title }> <div className={ styles.title }>
<h3>{ steps ? steps[current] : title }</h3> <h3>
{
steps
? steps[current]
: title
}
</h3>
{ this.renderSteps() } { this.renderSteps() }
{ this.renderWaiting() } { this.renderWaiting() }
</div> </div>
@ -63,10 +69,10 @@ export default class Title extends Component {
renderTimeline () { renderTimeline () {
const { steps } = this.props; const { steps } = this.props;
return steps.map((label) => { return steps.map((label, index) => {
return ( return (
<Step <Step
key={ label }> key={ label.key || index }>
<StepLabel> <StepLabel>
{ label } { label }
</StepLabel> </StepLabel>

View File

@ -14,16 +14,17 @@
/* 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/>.
*/ */
.actions { .actions {
background: rgba(0, 0, 0, 0.25) !important; background: rgba(0, 0, 0, 0.25) !important;
}
.actions button:not([disabled]) { button:not([disabled]) {
color: white !important; color: white !important;
}
.actions button:not([disabled]) svg { svg {
fill: white !important; fill: white !important;
}
}
} }
.body { .body {
@ -36,26 +37,26 @@
.content { .content {
transform: translate(0px, 0px) !important; transform: translate(0px, 0px) !important;
transition: none !important; transition: none !important;
}
.content>div { &>div {
background: rgba(0, 0, 0, 0.5) !important; background: rgba(0, 0, 0, 0.5) !important;
transition: none !important; transition: none !important;
}
} }
.title { .title {
background: rgba(0, 0, 0, 0.25) !important;
padding: 1em; padding: 1em;
margin-bottom: 0; margin-bottom: 0;
background: rgba(0, 0, 0, 0.25) !important;
}
.title h3 { h3 {
margin: 0; margin: 0;
text-transform: uppercase; text-transform: uppercase;
} }
.title .steps { .steps {
margin-bottom: -1em; margin-bottom: -1em;
}
} }
.waiting { .waiting {

View File

@ -14,10 +14,10 @@
// 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 { Dialog } from 'material-ui';
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import { Dialog } from 'material-ui';
import { nodeOrStringProptype } from '~/util/proptypes'; import { nodeOrStringProptype } from '~/util/proptypes';
@ -51,7 +51,7 @@ class Modal extends Component {
render () { render () {
const { muiTheme } = this.context; const { muiTheme } = this.context;
const { actions, busy, className, current, children, compact, steps, waiting, title, visible, settings } = this.props; const { actions, busy, children, className, current, compact, settings, steps, title, visible, waiting } = this.props;
const contentStyle = muiTheme.parity.getBackgroundStyle(null, settings.backgroundSeed); const contentStyle = muiTheme.parity.getBackgroundStyle(null, settings.backgroundSeed);
const header = ( const header = (
<Title <Title

View File

@ -33,6 +33,7 @@ import Errors from './Errors';
import Form, { AddressSelect, FormWrap, TypedInput, Input, InputAddress, InputAddressSelect, InputChip, InputInline, Select, RadioButtons } from './Form'; import Form, { AddressSelect, FormWrap, TypedInput, Input, InputAddress, InputAddressSelect, InputChip, InputInline, Select, RadioButtons } from './Form';
import GasPriceEditor from './GasPriceEditor'; import GasPriceEditor from './GasPriceEditor';
import GasPriceSelector from './GasPriceSelector'; import GasPriceSelector from './GasPriceSelector';
import Icons from './Icons';
import IdentityIcon from './IdentityIcon'; import IdentityIcon from './IdentityIcon';
import IdentityName from './IdentityName'; import IdentityName from './IdentityName';
import LanguageSelector from './LanguageSelector'; import LanguageSelector from './LanguageSelector';
@ -72,6 +73,7 @@ export {
FormWrap, FormWrap,
GasPriceEditor, GasPriceEditor,
GasPriceSelector, GasPriceSelector,
Icons,
Input, Input,
InputAddress, InputAddress,
InputAddressSelect, InputAddressSelect,

View File

@ -16,7 +16,7 @@
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { FirstRun } from '~/modals'; import { FirstRun, UpgradeParity } from '~/modals';
import { Errors, ParityBackground, Tooltips } from '~/ui'; import { Errors, ParityBackground, Tooltips } from '~/ui';
import styles from '../application.css'; import styles from '../application.css';
@ -28,20 +28,24 @@ export default class Container extends Component {
static propTypes = { static propTypes = {
children: PropTypes.node.isRequired, children: PropTypes.node.isRequired,
onCloseFirstRun: PropTypes.func,
showFirstRun: PropTypes.bool, showFirstRun: PropTypes.bool,
onCloseFirstRun: PropTypes.func upgradeStore: PropTypes.object.isRequired
}; };
render () { render () {
const { children, showFirstRun, onCloseFirstRun } = this.props;
const { muiTheme } = this.context; const { muiTheme } = this.context;
const { children, onCloseFirstRun, showFirstRun, upgradeStore } = this.props;
return ( return (
<ParityBackground className={ styles.container } muiTheme={ muiTheme }> <ParityBackground
className={ styles.container }
muiTheme={ muiTheme }>
<FirstRun <FirstRun
visible={ showFirstRun } onClose={ onCloseFirstRun }
onClose={ onCloseFirstRun } /> visible={ showFirstRun } />
<Tooltips /> <Tooltips />
<UpgradeParity store={ upgradeStore } />
<Errors /> <Errors />
{ children } { children }
</ParityBackground> </ParityBackground>

View File

@ -14,55 +14,52 @@
/* 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/>.
*/ */
.status { .status {
position: fixed; align-items: center;
background-color: rgba(0, 0, 0, 0.8);
bottom: 0; bottom: 0;
color: #ccc;
display: flex;
font-size: 0.75em;
left: 0; left: 0;
padding: .4em .5em;
position: fixed;
right: 0; right: 0;
z-index: 1000; z-index: 1000;
display: flex;
align-items: center;
padding: .4em .5em;
font-size: x-small;
color: #ccc;
background-color: rgba(0, 0, 0, 0.8);
}
.enode {
word-wrap: break-word;
}
.enode > * {
display: inline-block;
margin: 0 .25em;
vertical-align: middle;
}
.enode > :last-child {
margin-right: 0;
} }
.netinfo { .netinfo {
display: flex;
flex-grow: 1;
align-items: center;
color: #ddd; color: #ddd;
} flex-grow: 1;
text-align: right;
vertical-align: middle;
text-align: right;
.netinfo > * { div {
margin-left: 1em; display: inline-block;
margin-left: 1em;
}
} }
.network { .network {
padding: 0.25em 0.5em; border-radius: 0.4em;
border-radius: .4em;
line-height: 1.2; line-height: 1.2;
padding: 0.25em 0.5em;
text-transform: uppercase; text-transform: uppercase;
&.live {
background: rgb(0, 136, 0);
}
&.test {
background: rgb(136, 0, 0);
}
} }
.networklive { .upgrade {
background: rgb(0, 136, 0); div {
} display: inline-block;
margin-left: 1em;
.networktest { }
background: rgb(136, 0, 0);
} }

View File

@ -15,78 +15,118 @@
// 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 { connect } from 'react-redux'; import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import { BlockStatus } from '~/ui'; import { BlockStatus } from '~/ui';
import CopyToClipboard from '~/ui/CopyToClipboard';
import styles from './status.css'; import styles from './status.css';
class Status extends Component { class Status extends Component {
static propTypes = { static propTypes = {
blockNumber: PropTypes.object.isRequired,
clientVersion: PropTypes.string, clientVersion: PropTypes.string,
enode: PropTypes.string, isTest: PropTypes.bool,
netPeers: PropTypes.object,
netChain: PropTypes.string, netChain: PropTypes.string,
isTest: PropTypes.bool netPeers: PropTypes.object,
upgradeStore: PropTypes.object.isRequired
} }
render () { render () {
const { blockNumber, clientVersion, netChain, netPeers, isTest } = this.props; const { clientVersion, isTest, netChain, netPeers } = this.props;
const netStyle = `${styles.network} ${styles[isTest ? 'networktest' : 'networklive']}`;
if (!blockNumber) {
return null;
}
return ( return (
<div className={ styles.status }> <div className={ styles.status }>
<div className={ styles.version }> <div className={ styles.version }>
{ clientVersion } { clientVersion }
</div> </div>
<div className={ styles.upgrade }>
{ this.renderConsensus() }
{ this.renderUpgradeButton() }
</div>
<div className={ styles.netinfo }> <div className={ styles.netinfo }>
<BlockStatus /> <BlockStatus />
<div className={ netStyle }> <div className={ `${styles.network} ${styles[isTest ? 'test' : 'live']}` }>
{ isTest ? 'test' : netChain } { netChain }
</div> </div>
<div className={ styles.peers }> <div className={ styles.peers }>
{ netPeers.active.toFormat() }/{ netPeers.connected.toFormat() }/{ netPeers.max.toFormat() } peers { netPeers.active.toFormat() }/{ netPeers.connected.toFormat() }/{ netPeers.max.toFormat() } peers
</div> </div>
</div> </div>
{ this.renderEnode() }
</div> </div>
); );
} }
renderEnode () { renderConsensus () {
const { enode } = this.props; const { upgradeStore } = this.props;
if (!enode) { if (upgradeStore.consensusCapability === 'capable') {
return (
<div>
<FormattedMessage
id='application.status.consensus.capable'
defaultMessage='Capable' />
</div>
);
} else if (upgradeStore.consensusCapability.capableUntil) {
return (
<div>
<FormattedMessage
id='application.status.consensus.capableUntil'
defaultMessage='Capable until #{blockNumber}'
values={ {
blockNumber: upgradeStore.consensusCapability.capableUntil
} } />
</div>
);
} else if (upgradeStore.consensusCapability.incapableSince) {
return (
<div>
<FormattedMessage
id='application.status.consensus.incapableSince'
defaultMessage='Incapable since #{blockNumber}'
values={ {
blockNumber: upgradeStore.consensusCapability.incapableSince
} } />
</div>
);
}
return (
<div>
<FormattedMessage
id='application.status.consensus.unknown'
defaultMessage='Unknown capability' />
</div>
);
}
renderUpgradeButton () {
const { upgradeStore } = this.props;
if (!upgradeStore.available) {
return null; return null;
} }
const [protocol, rest] = enode.split('://');
const [id, host] = rest.split('@');
const abbreviated = `${protocol}://${id.slice(0, 3)}${id.slice(-3)}@${host}`;
return ( return (
<div className={ styles.enode }> <div>
<CopyToClipboard data={ enode } size={ 12 } /> <a
<div>{ abbreviated }</div> href='javascript:void(0)'
onClick={ upgradeStore.openModal }>
<FormattedMessage
id='application.status.upgrade'
defaultMessage='Upgrade' />
</a>
</div> </div>
); );
} }
} }
function mapStateToProps (state) { function mapStateToProps (state) {
const { blockNumber, clientVersion, enode, netPeers, netChain, isTest } = state.nodeStatus; const { clientVersion, netPeers, netChain, isTest } = state.nodeStatus;
return { return {
blockNumber,
clientVersion, clientVersion,
enode,
netPeers, netPeers,
netChain, netChain,
isTest isTest

View File

@ -22,5 +22,5 @@
} }
.content { .content {
padding-bottom: 1em; padding-bottom: 1.25em;
} }

View File

@ -19,6 +19,8 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import UpgradeStore from '~/modals/UpgradeParity/store';
import Connection from '../Connection'; import Connection from '../Connection';
import ParityBar from '../ParityBar'; import ParityBar from '../ParityBar';
@ -42,14 +44,15 @@ class Application extends Component {
} }
static propTypes = { static propTypes = {
blockNumber: PropTypes.object,
children: PropTypes.node, children: PropTypes.node,
netChain: PropTypes.string,
isTest: PropTypes.bool, isTest: PropTypes.bool,
pending: PropTypes.array, netChain: PropTypes.string,
blockNumber: PropTypes.object pending: PropTypes.array
} }
store = new Store(this.context.api); store = new Store(this.context.api);
upgradeStore = new UpgradeStore(this.context.api);
render () { render () {
const [root] = (window.location.hash || '').replace('#/', '').split('/'); const [root] = (window.location.hash || '').replace('#/', '').split('/');
@ -71,12 +74,13 @@ class Application extends Component {
} }
renderApp () { renderApp () {
const { children, pending, netChain, isTest, blockNumber } = this.props; const { blockNumber, children, pending, netChain, isTest } = this.props;
return ( return (
<Container <Container
showFirstRun={ this.store.firstrunVisible } upgradeStore={ this.upgradeStore }
onCloseFirstRun={ this.store.closeFirstrun }> onCloseFirstRun={ this.store.closeFirstrun }
showFirstRun={ this.store.firstrunVisible }>
<TabBar <TabBar
netChain={ netChain } netChain={ netChain }
isTest={ isTest } isTest={ isTest }
@ -84,7 +88,11 @@ class Application extends Component {
<div className={ styles.content }> <div className={ styles.content }>
{ children } { children }
</div> </div>
{ blockNumber ? (<Status />) : null } {
blockNumber
? <Status upgradeStore={ this.upgradeStore } />
: null
}
<Snackbar /> <Snackbar />
</Container> </Container>
); );
@ -102,16 +110,16 @@ class Application extends Component {
} }
function mapStateToProps (state) { function mapStateToProps (state) {
const { netChain, isTest, blockNumber } = state.nodeStatus; const { blockNumber, netChain, isTest } = state.nodeStatus;
const { hasAccounts } = state.personal; const { hasAccounts } = state.personal;
const { pending } = state.signer; const { pending } = state.signer;
return { return {
blockNumber,
hasAccounts, hasAccounts,
netChain,
isTest, isTest,
pending, netChain,
blockNumber pending
}; };
} }

View File

@ -20,12 +20,12 @@
.row { .row {
margin: 0 -1em; margin: 0 -1em;
}
.row::after { &::after {
display: table; display: table;
clear: both; clear: both;
content: ''; content: '';
}
} }
.blockInfo { .blockInfo {
@ -44,7 +44,7 @@
} }
.col, .col,
.col1, .col2, .col3, .col4, .col5, .col6, .col7, .col8, .col9, .col10, .col11, .col12 { .col3, .col4_5, .col6, .col12 {
float: left; float: left;
padding: 0 1em; padding: 0 1em;
box-sizing: border-box; box-sizing: border-box;
@ -57,18 +57,11 @@
width: calc(100% / 12 * 3); width: calc(100% / 12 * 3);
} }
.col4 { .col4_5 {
width: 33.33333%; width: 37.5%;
width: -webkit-calc(100% / 12 * 4); width: -webkit-calc(100% / 12 * 4.5);
width: -moz-calc(100% / 12 * 4); width: -moz-calc(100% / 12 * 4.5);
width: calc(100% / 12 * 4); width: calc(100% / 12 * 4.5);
}
.col5 {
width: 41.66665%;
width: -webkit-calc(100% / 12 * 5);
width: -moz-calc(100% / 12 * 5);
width: calc(100% / 12 * 5);
} }
.col6 { .col6 {

View File

@ -68,13 +68,13 @@ export default class Status extends Component {
</div> </div>
</div> </div>
</div> </div>
<div className={ styles.col5 }> <div className={ styles.col4_5 }>
<MiningSettings <MiningSettings
{ ...this._test('mining') } { ...this._test('mining') }
nodeStatus={ nodeStatus } nodeStatus={ nodeStatus }
actions={ this.props.actions } /> actions={ this.props.actions } />
</div> </div>
<div className={ styles.col4 }> <div className={ styles.col4_5 }>
{ this.renderSettings() } { this.renderSettings() }
</div> </div>
</div> </div>
@ -102,6 +102,7 @@ export default class Status extends Component {
<div { ...this._test('settings') }> <div { ...this._test('settings') }>
<ContainerTitle title='network settings' /> <ContainerTitle title='network settings' />
<Input <Input
allowCopy
readOnly readOnly
label='chain' label='chain'
value={ nodeStatus.netChain } value={ nodeStatus.netChain }
@ -109,6 +110,7 @@ export default class Status extends Component {
<div className={ styles.row }> <div className={ styles.row }>
<div className={ styles.col6 }> <div className={ styles.col6 }>
<Input <Input
allowCopy
readOnly readOnly
label='peers' label='peers'
value={ peers } value={ peers }
@ -116,6 +118,7 @@ export default class Status extends Component {
</div> </div>
<div className={ styles.col6 }> <div className={ styles.col6 }>
<Input <Input
allowCopy
readOnly readOnly
label='network port' label='network port'
value={ nodeStatus.netPort.toString() } value={ nodeStatus.netPort.toString() }
@ -124,6 +127,7 @@ export default class Status extends Component {
</div> </div>
<Input <Input
allowCopy
readOnly readOnly
label='rpc enabled' label='rpc enabled'
value={ rpcSettings.enabled ? 'yes' : 'no' } value={ rpcSettings.enabled ? 'yes' : 'no' }
@ -131,6 +135,7 @@ export default class Status extends Component {
<div className={ styles.row }> <div className={ styles.row }>
<div className={ styles.col6 }> <div className={ styles.col6 }>
<Input <Input
allowCopy
readOnly readOnly
label='rpc interface' label='rpc interface'
value={ rpcSettings.interface } value={ rpcSettings.interface }
@ -138,12 +143,24 @@ export default class Status extends Component {
</div> </div>
<div className={ styles.col6 }> <div className={ styles.col6 }>
<Input <Input
allowCopy
readOnly readOnly
label='rpc port' label='rpc port'
value={ rpcSettings.port.toString() } value={ rpcSettings.port.toString() }
{ ...this._test('rpc-port') } /> { ...this._test('rpc-port') } />
</div> </div>
</div> </div>
<div className={ styles.row }>
<div className={ styles.col12 }>
<Input
allowCopy
readOnly
label='enode'
value={ nodeStatus.enode }
{ ...this._test('node-enode') } />
</div>
</div>
</div> </div>
); );
} }

View File

@ -27,12 +27,12 @@ extern crate time;
extern crate lazy_static; extern crate lazy_static;
use std::{env, thread, fs}; use std::{env, thread, fs};
use std::sync::Arc; use std::sync::{Weak, Arc};
use std::io::Write; use std::io::Write;
use isatty::{stderr_isatty, stdout_isatty}; use isatty::{stderr_isatty, stdout_isatty};
use env_logger::LogBuilder; use env_logger::LogBuilder;
use regex::Regex; use regex::Regex;
use util::RotatingLogger; use util::{Mutex, RotatingLogger} ;
use util::log::Colour; use util::log::Colour;
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
@ -52,6 +52,10 @@ impl Default for Config {
} }
} }
lazy_static! {
static ref ROTATING_LOGGER : Mutex<Weak<RotatingLogger>> = Mutex::new(Default::default());
}
/// Sets up the logger /// Sets up the logger
pub fn setup_log(config: &Config) -> Result<Arc<RotatingLogger>, String> { pub fn setup_log(config: &Config) -> Result<Arc<RotatingLogger>, String> {
use rlog::*; use rlog::*;
@ -121,9 +125,17 @@ pub fn setup_log(config: &Config) -> Result<Arc<RotatingLogger>, String> {
}; };
builder.format(format); builder.format(format);
builder.init().expect("Logger initialized only once."); builder.init()
.and_then(|_| {
Ok(logs) *ROTATING_LOGGER.lock() = Arc::downgrade(&logs);
Ok(logs)
})
// couldn't create new logger - try to fall back on previous logger.
.or_else(|err| match ROTATING_LOGGER.lock().upgrade() {
Some(l) => Ok(l),
// no previous logger. fatal.
None => Err(format!("{:?}", err)),
})
} }
fn kill_color(s: &str) -> String { fn kill_color(s: &str) -> String {

View File

@ -32,7 +32,6 @@ use ethcore::verification::queue::VerifierSettings;
use cache::CacheConfig; use cache::CacheConfig;
use informant::{Informant, MillisecondDuration}; use informant::{Informant, MillisecondDuration};
use params::{SpecType, Pruning, Switch, tracing_switch_to_bool, fatdb_switch_to_bool}; use params::{SpecType, Pruning, Switch, tracing_switch_to_bool, fatdb_switch_to_bool};
use io_handler::ImportIoHandler;
use helpers::{to_client_config, execute_upgrades}; use helpers::{to_client_config, execute_upgrades};
use dir::Directories; use dir::Directories;
use user_defaults::UserDefaults; use user_defaults::UserDefaults;
@ -134,7 +133,7 @@ pub struct ExportState {
pub max_balance: Option<U256>, pub max_balance: Option<U256>,
} }
pub fn execute(cmd: BlockchainCmd) -> Result<String, String> { pub fn execute(cmd: BlockchainCmd) -> Result<(), String> {
match cmd { match cmd {
BlockchainCmd::Kill(kill_cmd) => kill_db(kill_cmd), BlockchainCmd::Kill(kill_cmd) => kill_db(kill_cmd),
BlockchainCmd::Import(import_cmd) => execute_import(import_cmd), BlockchainCmd::Import(import_cmd) => execute_import(import_cmd),
@ -143,7 +142,7 @@ pub fn execute(cmd: BlockchainCmd) -> Result<String, String> {
} }
} }
fn execute_import(cmd: ImportBlockchain) -> Result<String, String> { fn execute_import(cmd: ImportBlockchain) -> Result<(), String> {
let timer = Instant::now(); let timer = Instant::now();
// Setup panic handler // Setup panic handler
@ -239,11 +238,8 @@ fn execute_import(cmd: ImportBlockchain) -> Result<String, String> {
} }
}; };
let informant = Informant::new(client.clone(), None, None, None, cmd.with_color); let informant = Arc::new(Informant::new(client.clone(), None, None, None, cmd.with_color));
service.register_io_handler(informant).map_err(|_| "Unable to register informant handler".to_owned())?;
try!(service.register_io_handler(Arc::new(ImportIoHandler {
info: Arc::new(informant),
})).map_err(|_| "Unable to register informant handler".to_owned()));
let do_import = |bytes| { let do_import = |bytes| {
while client.queue_info().is_full() { sleep(Duration::from_secs(1)); } while client.queue_info().is_full() { sleep(Duration::from_secs(1)); }
@ -259,7 +255,6 @@ fn execute_import(cmd: ImportBlockchain) -> Result<String, String> {
Ok(()) Ok(())
}; };
match format { match format {
DataFormat::Binary => { DataFormat::Binary => {
loop { loop {
@ -298,7 +293,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result<String, String> {
let report = client.report(); let report = client.report();
let ms = timer.elapsed().as_milliseconds(); let ms = timer.elapsed().as_milliseconds();
Ok(format!("Import completed in {} seconds, {} blocks, {} blk/s, {} transactions, {} tx/s, {} Mgas, {} Mgas/s", info!("Import completed in {} seconds, {} blocks, {} blk/s, {} transactions, {} tx/s, {} Mgas, {} Mgas/s",
ms / 1000, ms / 1000,
report.blocks_imported, report.blocks_imported,
(report.blocks_imported * 1000) as u64 / ms, (report.blocks_imported * 1000) as u64 / ms,
@ -306,7 +301,8 @@ fn execute_import(cmd: ImportBlockchain) -> Result<String, String> {
(report.transactions_applied * 1000) as u64 / ms, (report.transactions_applied * 1000) as u64 / ms,
report.gas_processed / From::from(1_000_000), report.gas_processed / From::from(1_000_000),
(report.gas_processed / From::from(ms * 1000)).low_u64(), (report.gas_processed / From::from(ms * 1000)).low_u64(),
).into()) );
Ok(())
} }
fn start_client( fn start_client(
@ -318,7 +314,8 @@ fn start_client(
fat_db: Switch, fat_db: Switch,
compaction: DatabaseCompactionProfile, compaction: DatabaseCompactionProfile,
wal: bool, wal: bool,
cache_config: CacheConfig) -> Result<ClientService, String> { cache_config: CacheConfig
) -> Result<ClientService, String> {
// load spec file // load spec file
let spec = try!(spec.spec()); let spec = try!(spec.spec());
@ -372,7 +369,7 @@ fn start_client(
Ok(service) Ok(service)
} }
fn execute_export(cmd: ExportBlockchain) -> Result<String, String> { fn execute_export(cmd: ExportBlockchain) -> Result<(), String> {
// Setup panic handler // Setup panic handler
let service = try!(start_client(cmd.dirs, cmd.spec, cmd.pruning, cmd.pruning_history, cmd.tracing, cmd.fat_db, cmd.compaction, cmd.wal, cmd.cache_config)); let service = try!(start_client(cmd.dirs, cmd.spec, cmd.pruning, cmd.pruning_history, cmd.tracing, cmd.fat_db, cmd.compaction, cmd.wal, cmd.cache_config));
let panic_handler = PanicHandler::new_in_arc(); let panic_handler = PanicHandler::new_in_arc();
@ -400,10 +397,11 @@ fn execute_export(cmd: ExportBlockchain) -> Result<String, String> {
} }
} }
Ok("Export completed.".into()) info!("Export completed.");
Ok(())
} }
fn execute_export_state(cmd: ExportState) -> Result<String, String> { fn execute_export_state(cmd: ExportState) -> Result<(), String> {
// Setup panic handler // Setup panic handler
let service = try!(start_client(cmd.dirs, cmd.spec, cmd.pruning, cmd.pruning_history, cmd.tracing, cmd.fat_db, cmd.compaction, cmd.wal, cmd.cache_config)); let service = try!(start_client(cmd.dirs, cmd.spec, cmd.pruning, cmd.pruning_history, cmd.tracing, cmd.fat_db, cmd.compaction, cmd.wal, cmd.cache_config));
let panic_handler = PanicHandler::new_in_arc(); let panic_handler = PanicHandler::new_in_arc();
@ -479,10 +477,11 @@ fn execute_export_state(cmd: ExportState) -> Result<String, String> {
} }
} }
out.write_fmt(format_args!("\n]}}")).expect("Write error"); out.write_fmt(format_args!("\n]}}")).expect("Write error");
Ok("Export completed.".into()) info!("Export completed.");
Ok(())
} }
pub fn kill_db(cmd: KillBlockchain) -> Result<String, String> { pub fn kill_db(cmd: KillBlockchain) -> Result<(), String> {
let spec = try!(cmd.spec.spec()); let spec = try!(cmd.spec.spec());
let genesis_hash = spec.genesis_header().hash(); let genesis_hash = spec.genesis_header().hash();
let db_dirs = cmd.dirs.database(genesis_hash, None, spec.data_dir); let db_dirs = cmd.dirs.database(genesis_hash, None, spec.data_dir);
@ -491,7 +490,8 @@ pub fn kill_db(cmd: KillBlockchain) -> Result<String, String> {
let algorithm = cmd.pruning.to_algorithm(&user_defaults); let algorithm = cmd.pruning.to_algorithm(&user_defaults);
let dir = db_dirs.db_path(algorithm); let dir = db_dirs.db_path(algorithm);
try!(fs::remove_dir_all(&dir).map_err(|e| format!("Error removing database: {:?}", e))); try!(fs::remove_dir_all(&dir).map_err(|e| format!("Error removing database: {:?}", e)));
Ok("Database deleted.".to_owned()) info!("Database deleted.");
Ok(())
} }
#[cfg(test)] #[cfg(test)]

View File

@ -2,6 +2,11 @@
mode = "last" mode = "last"
mode_timeout = 300 mode_timeout = 300
mode_alarm = 3600 mode_alarm = 3600
auto_update = "critical"
release_track = "current"
no_download = false
no_consensus = false
chain = "homestead" chain = "homestead"
db_path = "$HOME/.parity" db_path = "$HOME/.parity"
keys_path = "$HOME/.parity/keys" keys_path = "$HOME/.parity/keys"

View File

@ -85,6 +85,10 @@ usage! {
flag_mode: String = "last", or |c: &Config| otry!(c.parity).mode.clone(), flag_mode: String = "last", or |c: &Config| otry!(c.parity).mode.clone(),
flag_mode_timeout: u64 = 300u64, or |c: &Config| otry!(c.parity).mode_timeout.clone(), flag_mode_timeout: u64 = 300u64, or |c: &Config| otry!(c.parity).mode_timeout.clone(),
flag_mode_alarm: u64 = 3600u64, or |c: &Config| otry!(c.parity).mode_alarm.clone(), flag_mode_alarm: u64 = 3600u64, or |c: &Config| otry!(c.parity).mode_alarm.clone(),
flag_auto_update: String = "critical", or |c: &Config| otry!(c.parity).auto_update.clone(),
flag_release_track: String = "current", or |c: &Config| otry!(c.parity).release_track.clone(),
flag_no_download: bool = false, or |c: &Config| otry!(c.parity).no_download.clone(),
flag_no_consensus: bool = false, or |c: &Config| otry!(c.parity).no_consensus.clone(),
flag_chain: String = "homestead", or |c: &Config| otry!(c.parity).chain.clone(), flag_chain: String = "homestead", or |c: &Config| otry!(c.parity).chain.clone(),
flag_db_path: String = default_data_path(), or |c: &Config| otry!(c.parity).db_path.clone(), flag_db_path: String = default_data_path(), or |c: &Config| otry!(c.parity).db_path.clone(),
flag_keys_path: String = "$DATA/keys", or |c: &Config| otry!(c.parity).keys_path.clone(), flag_keys_path: String = "$DATA/keys", or |c: &Config| otry!(c.parity).keys_path.clone(),
@ -309,6 +313,10 @@ struct Operating {
mode: Option<String>, mode: Option<String>,
mode_timeout: Option<u64>, mode_timeout: Option<u64>,
mode_alarm: Option<u64>, mode_alarm: Option<u64>,
auto_update: Option<String>,
release_track: Option<String>,
no_download: Option<bool>,
no_consensus: Option<bool>,
chain: Option<String>, chain: Option<String>,
db_path: Option<String>, db_path: Option<String>,
keys_path: Option<String>, keys_path: Option<String>,
@ -533,6 +541,10 @@ mod tests {
flag_mode: "last".into(), flag_mode: "last".into(),
flag_mode_timeout: 300u64, flag_mode_timeout: 300u64,
flag_mode_alarm: 3600u64, flag_mode_alarm: 3600u64,
flag_auto_update: "critical".into(),
flag_release_track: "current".into(),
flag_no_download: false,
flag_no_consensus: false,
flag_chain: "xyz".into(), flag_chain: "xyz".into(),
flag_db_path: "$HOME/.parity".into(), flag_db_path: "$HOME/.parity".into(),
flag_keys_path: "$HOME/.parity/keys".into(), flag_keys_path: "$HOME/.parity/keys".into(),
@ -707,6 +719,10 @@ mod tests {
mode: Some("dark".into()), mode: Some("dark".into()),
mode_timeout: Some(15u64), mode_timeout: Some(15u64),
mode_alarm: Some(10u64), mode_alarm: Some(10u64),
auto_update: None,
release_track: None,
no_download: None,
no_consensus: None,
chain: Some("./chain.json".into()), chain: Some("./chain.json".into()),
db_path: None, db_path: None,
keys_path: None, keys_path: None,

View File

@ -34,6 +34,27 @@ Operating Options:
--mode-alarm SECS Specify the number of seconds before auto sleep --mode-alarm SECS Specify the number of seconds before auto sleep
reawake timeout occurs when mode is passive reawake timeout occurs when mode is passive
(default: {flag_mode_alarm}). (default: {flag_mode_alarm}).
--auto-update SET Set a releases set to automatically update and
install.
all - All updates in the our release track.
critical - Only consensus/security updates.
none - No updates will be auto-installed.
(default: {flag_auto_update}).
--release-track TRACK Set which release track we should use for updates.
stable - Stable releases.
beta - Beta releases.
nightly - Nightly releases (unstable).
testing - Testing releases (do not use).
current - Whatever track this executable was
released on (default: {flag_release_track}).
--no-download Normally new releases will be downloaded ready for
updating. This disables it. Not recommended.
(default: {flag_no_download}).
--no-consensus Force the binary to run even if there are known
issues regarding consensus. Not recommended.
(default: {flag_no_consensus}).
--force-direct Run the originally installed version of Parity,
ignoring any updates that have since been installed.
--chain CHAIN Specify the blockchain type. CHAIN may be either a --chain CHAIN Specify the blockchain type. CHAIN may be either a
JSON chain specification file or olympic, frontier, JSON chain specification file or olympic, frontier,
homestead, mainnet, morden, ropsten, classic, expanse, homestead, mainnet, morden, ropsten, classic, expanse,
@ -339,6 +360,9 @@ Legacy Options:
--extradata STRING Equivalent to --extra-data STRING. --extradata STRING Equivalent to --extra-data STRING.
--cache MB Equivalent to --cache-size MB. --cache MB Equivalent to --cache-size MB.
Internal Options:
--can-restart Executable will auto-restart if exiting with 69.
Miscellaneous Options: Miscellaneous Options:
-c --config CONFIG Specify a filename containing a configuration file. -c --config CONFIG Specify a filename containing a configuration file.
(default: {flag_config}) (default: {flag_config})

View File

@ -23,7 +23,7 @@ use cli::{Args, ArgsError};
use util::{Hashable, U256, Uint, Bytes, version_data, Secret, Address}; use util::{Hashable, U256, Uint, Bytes, version_data, Secret, Address};
use util::log::Colour; use util::log::Colour;
use ethsync::{NetworkConfiguration, is_valid_node_url, AllowIP}; use ethsync::{NetworkConfiguration, is_valid_node_url, AllowIP};
use ethcore::client::VMType; use ethcore::client::{VMType};
use ethcore::miner::{MinerOptions, Banning}; use ethcore::miner::{MinerOptions, Banning};
use ethcore::verification::queue::VerifierSettings; use ethcore::verification::queue::VerifierSettings;
@ -34,9 +34,10 @@ use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_pri
geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address, to_gas_limit, to_queue_strategy}; geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address, to_gas_limit, to_queue_strategy};
use params::{ResealPolicy, AccountsConfig, GasPricerConfig, MinerExtras}; use params::{ResealPolicy, AccountsConfig, GasPricerConfig, MinerExtras};
use ethcore_logger::Config as LogConfig; use ethcore_logger::Config as LogConfig;
use dir::Directories; use dir::{Directories, default_hypervisor_path};
use dapps::Configuration as DappsConfiguration; use dapps::Configuration as DappsConfiguration;
use signer::{Configuration as SignerConfiguration}; use signer::{Configuration as SignerConfiguration};
use updater::{UpdatePolicy, UpdateFilter, ReleaseTrack};
use run::RunCmd; use run::RunCmd;
use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, KillBlockchain, ExportState, DataFormat}; use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, KillBlockchain, ExportState, DataFormat};
use presale::ImportWallet; use presale::ImportWallet;
@ -99,6 +100,7 @@ impl Configuration {
let pruning_history = self.args.flag_pruning_history; let pruning_history = self.args.flag_pruning_history;
let vm_type = try!(self.vm_type()); let vm_type = try!(self.vm_type());
let mode = match self.args.flag_mode.as_ref() { "last" => None, mode => Some(try!(to_mode(&mode, self.args.flag_mode_timeout, self.args.flag_mode_alarm))), }; let mode = match self.args.flag_mode.as_ref() { "last" => None, mode => Some(try!(to_mode(&mode, self.args.flag_mode_timeout, self.args.flag_mode_alarm))), };
let update_policy = try!(self.update_policy());
let miner_options = try!(self.miner_options()); let miner_options = try!(self.miner_options());
let logger_config = self.logger_config(); let logger_config = self.logger_config();
let http_conf = try!(self.http_config()); let http_conf = try!(self.http_config());
@ -320,6 +322,7 @@ impl Configuration {
acc_conf: try!(self.accounts_config()), acc_conf: try!(self.accounts_config()),
gas_pricer: try!(self.gas_pricer_config()), gas_pricer: try!(self.gas_pricer_config()),
miner_extras: try!(self.miner_extras()), miner_extras: try!(self.miner_extras()),
update_policy: update_policy,
mode: mode, mode: mode,
tracing: tracing, tracing: tracing,
fat_db: fat_db, fat_db: fat_db,
@ -680,6 +683,28 @@ impl Configuration {
} }
} }
fn update_policy(&self) -> Result<UpdatePolicy, String> {
Ok(UpdatePolicy {
enable_downloading: !self.args.flag_no_download,
require_consensus: !self.args.flag_no_consensus,
filter: match self.args.flag_auto_update.as_ref() {
"none" => UpdateFilter::None,
"critical" => UpdateFilter::Critical,
"all" => UpdateFilter::All,
_ => return Err("Invalid value for `--auto-update`. See `--help` for more information.".into()),
},
track: match self.args.flag_release_track.as_ref() {
"stable" => ReleaseTrack::Stable,
"beta" => ReleaseTrack::Beta,
"nightly" => ReleaseTrack::Nightly,
"testing" => ReleaseTrack::Testing,
"current" => ReleaseTrack::Unknown,
_ => return Err("Invalid value for `--releases-track`. See `--help` for more information.".into()),
},
path: default_hypervisor_path(),
})
}
fn directories(&self) -> Directories { fn directories(&self) -> Directories {
use util::path; use util::path;
@ -786,13 +811,14 @@ mod tests {
use ethcore::miner::{MinerOptions, PrioritizationStrategy}; use ethcore::miner::{MinerOptions, PrioritizationStrategy};
use helpers::{default_network_config}; use helpers::{default_network_config};
use run::RunCmd; use run::RunCmd;
use dir::Directories; use dir::{Directories, default_hypervisor_path};
use signer::{Configuration as SignerConfiguration}; use signer::{Configuration as SignerConfiguration};
use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, DataFormat, ExportState}; use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, DataFormat, ExportState};
use presale::ImportWallet; use presale::ImportWallet;
use params::SpecType; use params::SpecType;
use account::{AccountCmd, NewAccount, ImportAccounts, ListAccounts}; use account::{AccountCmd, NewAccount, ImportAccounts, ListAccounts};
use devtools::{RandomTempPath}; use devtools::{RandomTempPath};
use updater::{UpdatePolicy, UpdateFilter, ReleaseTrack};
use std::io::Write; use std::io::Write;
use std::fs::{File, create_dir}; use std::fs::{File, create_dir};
@ -986,6 +1012,7 @@ mod tests {
acc_conf: Default::default(), acc_conf: Default::default(),
gas_pricer: Default::default(), gas_pricer: Default::default(),
miner_extras: Default::default(), miner_extras: Default::default(),
update_policy: UpdatePolicy { enable_downloading: true, require_consensus: true, filter: UpdateFilter::Critical, track: ReleaseTrack::Unknown, path: default_hypervisor_path() },
mode: Default::default(), mode: Default::default(),
tracing: Default::default(), tracing: Default::default(),
compaction: Default::default(), compaction: Default::default(),
@ -1029,6 +1056,21 @@ mod tests {
assert_eq!(conf3.miner_options().unwrap(), mining_options); assert_eq!(conf3.miner_options().unwrap(), mining_options);
} }
#[test]
fn should_parse_updater_options() {
// when
let conf0 = parse(&["parity", "--release-track=testing"]);
let conf1 = parse(&["parity", "--auto-update", "all", "--no-consensus"]);
let conf2 = parse(&["parity", "--no-download", "--auto-update=all", "--release-track=beta"]);
let conf3 = parse(&["parity", "--auto-update=xxx"]);
// then
assert_eq!(conf0.update_policy().unwrap(), UpdatePolicy{enable_downloading: true, require_consensus: true, filter: UpdateFilter::Critical, track: ReleaseTrack::Testing, path: default_hypervisor_path()});
assert_eq!(conf1.update_policy().unwrap(), UpdatePolicy{enable_downloading: true, require_consensus: false, filter: UpdateFilter::All, track: ReleaseTrack::Unknown, path: default_hypervisor_path()});
assert_eq!(conf2.update_policy().unwrap(), UpdatePolicy{enable_downloading: false, require_consensus: true, filter: UpdateFilter::All, track: ReleaseTrack::Beta, path: default_hypervisor_path()});
assert!(conf3.update_policy().is_err());
}
#[test] #[test]
fn should_parse_network_settings() { fn should_parse_network_settings() {
// given // given

View File

@ -195,6 +195,11 @@ pub fn default_data_path() -> String {
get_app_root(AppDataType::UserData, &app_info).map(|p| p.to_string_lossy().into_owned()).unwrap_or_else(|_| "$HOME/.parity".to_owned()) get_app_root(AppDataType::UserData, &app_info).map(|p| p.to_string_lossy().into_owned()).unwrap_or_else(|_| "$HOME/.parity".to_owned())
} }
pub fn default_hypervisor_path() -> String {
let app_info = AppInfo { name: "parity-hypervisor", author: "parity" };
get_app_root(AppDataType::UserData, &app_info).map(|p| p.to_string_lossy().into_owned()).unwrap_or_else(|_| "$HOME/.parity-hypervisor".to_owned())
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Directories; use super::Directories;

View File

@ -19,12 +19,14 @@ use self::ansi_term::Colour::{White, Yellow, Green, Cyan, Blue};
use self::ansi_term::Style; use self::ansi_term::Style;
use std::sync::{Arc}; use std::sync::{Arc};
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering};
use std::time::{Instant, Duration}; use std::time::{Instant, Duration};
use io::{TimerToken, IoContext, IoHandler};
use isatty::{stdout_isatty}; use isatty::{stdout_isatty};
use ethsync::{SyncProvider, ManageNetwork}; use ethsync::{SyncProvider, ManageNetwork};
use util::{Uint, RwLock, Mutex, H256, Colour, Bytes}; use util::{Uint, RwLock, Mutex, H256, Colour, Bytes};
use ethcore::client::*; use ethcore::client::*;
use ethcore::service::ClientIoMessage;
use ethcore::views::BlockView; use ethcore::views::BlockView;
use ethcore::snapshot::service::Service as SnapshotService; use ethcore::snapshot::service::Service as SnapshotService;
use ethcore::snapshot::{RestorationStatus, SnapshotService as SS}; use ethcore::snapshot::{RestorationStatus, SnapshotService as SS};
@ -44,6 +46,7 @@ pub struct Informant {
last_import: Mutex<Instant>, last_import: Mutex<Instant>,
skipped: AtomicUsize, skipped: AtomicUsize,
skipped_txs: AtomicUsize, skipped_txs: AtomicUsize,
in_shutdown: AtomicBool,
} }
/// Format byte counts to standard denominations. /// Format byte counts to standard denominations.
@ -82,9 +85,14 @@ impl Informant {
last_import: Mutex::new(Instant::now()), last_import: Mutex::new(Instant::now()),
skipped: AtomicUsize::new(0), skipped: AtomicUsize::new(0),
skipped_txs: AtomicUsize::new(0), skipped_txs: AtomicUsize::new(0),
in_shutdown: AtomicBool::new(false),
} }
} }
/// Signal that we're shutting down; no more output necessary.
pub fn shutdown(&self) {
self.in_shutdown.store(true, ::std::sync::atomic::Ordering::SeqCst);
}
#[cfg_attr(feature="dev", allow(match_bool))] #[cfg_attr(feature="dev", allow(match_bool))]
pub fn tick(&self) { pub fn tick(&self) {
@ -221,3 +229,16 @@ impl ChainNotify for Informant {
} }
} }
const INFO_TIMER: TimerToken = 0;
impl IoHandler<ClientIoMessage> for Informant {
fn initialize(&self, io: &IoContext<ClientIoMessage>) {
io.register_timer(INFO_TIMER, 5000).expect("Error registering timer");
}
fn timeout(&self, _io: &IoContext<ClientIoMessage>, timer: TimerToken) {
if timer == INFO_TIMER && !self.in_shutdown.load(AtomicOrdering::SeqCst) {
self.tick();
}
}
}

View File

@ -1,64 +0,0 @@
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use ethcore::client::Client;
use ethcore::service::ClientIoMessage;
use ethsync::{SyncProvider, ManageNetwork};
use ethcore::account_provider::AccountProvider;
use io::{TimerToken, IoHandler, IoContext};
use informant::Informant;
const INFO_TIMER: TimerToken = 0;
pub struct ClientIoHandler {
pub client: Arc<Client>,
pub sync: Arc<SyncProvider>,
pub net: Arc<ManageNetwork>,
pub accounts: Arc<AccountProvider>,
pub info: Arc<Informant>,
pub shutdown: Arc<AtomicBool>
}
impl IoHandler<ClientIoMessage> for ClientIoHandler {
fn initialize(&self, io: &IoContext<ClientIoMessage>) {
io.register_timer(INFO_TIMER, 5000).expect("Error registering timer");
}
fn timeout(&self, _io: &IoContext<ClientIoMessage>, timer: TimerToken) {
if timer == INFO_TIMER && !self.shutdown.load(Ordering::SeqCst) {
self.info.tick();
}
}
}
pub struct ImportIoHandler {
pub info: Arc<Informant>,
}
impl IoHandler<ClientIoMessage> for ImportIoHandler {
fn initialize(&self, io: &IoContext<ClientIoMessage>) {
io.register_timer(INFO_TIMER, 5000).expect("Error registering timer");
}
fn timeout(&self, _io: &IoContext<ClientIoMessage>, timer: TimerToken) {
if let INFO_TIMER = timer {
self.info.tick()
}
}
}

View File

@ -42,13 +42,14 @@ extern crate ethcore_ipc_nano as nanoipc;
extern crate serde; extern crate serde;
extern crate serde_json; extern crate serde_json;
extern crate rlp; extern crate rlp;
extern crate ethcore_hash_fetch as hash_fetch;
extern crate ethcore_light as light; extern crate ethcore_light as light;
extern crate parity_hash_fetch as hash_fetch;
extern crate ethcore_ipc_hypervisor as hypervisor; extern crate ethcore_ipc_hypervisor as hypervisor;
extern crate ethcore_rpc; extern crate ethcore_rpc;
extern crate ethcore_signer; extern crate ethcore_signer;
extern crate parity_updater as updater;
extern crate ansi_term; extern crate ansi_term;
extern crate regex; extern crate regex;
@ -90,7 +91,6 @@ mod upgrade;
mod rpc; mod rpc;
mod dapps; mod dapps;
mod informant; mod informant;
mod io_handler;
mod cli; mod cli;
mod configuration; mod configuration;
mod migration; mod migration;
@ -117,13 +117,16 @@ mod user_defaults;
mod stratum; mod stratum;
use std::{process, env}; use std::{process, env};
use std::io::{self as stdio, BufReader, Write}; use std::collections::HashMap;
use std::io::{self as stdio, BufReader, Read, Write};
use std::fs::File; use std::fs::File;
use std::path::PathBuf;
use util::sha3::sha3; use util::sha3::sha3;
use cli::Args; use cli::Args;
use configuration::{Cmd, Execute, Configuration}; use configuration::{Cmd, Execute, Configuration};
use deprecated::find_deprecated; use deprecated::find_deprecated;
use ethcore_logger::setup_log; use ethcore_logger::setup_log;
use dir::default_hypervisor_path;
fn print_hash_of(maybe_file: Option<String>) -> Result<String, String> { fn print_hash_of(maybe_file: Option<String>) -> Result<String, String> {
if let Some(file) = maybe_file { if let Some(file) = maybe_file {
@ -135,31 +138,34 @@ fn print_hash_of(maybe_file: Option<String>) -> Result<String, String> {
} }
} }
fn execute(command: Execute) -> Result<String, String> { enum PostExecutionAction {
Print(String),
Restart,
Quit,
}
fn execute(command: Execute, can_restart: bool) -> Result<PostExecutionAction, String> {
let logger = setup_log(&command.logger).expect("Logger is initialized only once; qed"); let logger = setup_log(&command.logger).expect("Logger is initialized only once; qed");
match command.cmd { match command.cmd {
Cmd::Run(run_cmd) => { Cmd::Run(run_cmd) => {
try!(run::execute(run_cmd, logger)); let restart = run::execute(run_cmd, can_restart, logger)?;
Ok("".into()) Ok(if restart { PostExecutionAction::Restart } else { PostExecutionAction::Quit })
}, },
Cmd::Version => Ok(Args::print_version()), Cmd::Version => Ok(PostExecutionAction::Print(Args::print_version())),
Cmd::Hash(maybe_file) => print_hash_of(maybe_file), Cmd::Hash(maybe_file) => print_hash_of(maybe_file).map(|s| PostExecutionAction::Print(s)),
Cmd::Account(account_cmd) => account::execute(account_cmd), Cmd::Account(account_cmd) => account::execute(account_cmd).map(|s| PostExecutionAction::Print(s)),
Cmd::ImportPresaleWallet(presale_cmd) => presale::execute(presale_cmd), Cmd::ImportPresaleWallet(presale_cmd) => presale::execute(presale_cmd).map(|s| PostExecutionAction::Print(s)),
Cmd::Blockchain(blockchain_cmd) => blockchain::execute(blockchain_cmd), Cmd::Blockchain(blockchain_cmd) => blockchain::execute(blockchain_cmd).map(|_| PostExecutionAction::Quit),
Cmd::SignerToken(signer_cmd) => signer::execute(signer_cmd), Cmd::SignerToken(signer_cmd) => signer::execute(signer_cmd).map(|s| PostExecutionAction::Print(s)),
Cmd::SignerSign { id, pwfile, port, authfile } => Cmd::SignerSign { id, pwfile, port, authfile } => rpc_cli::signer_sign(id, pwfile, port, authfile).map(|s| PostExecutionAction::Print(s)),
rpc_cli::cmd_signer_sign(id, pwfile, port, authfile), Cmd::SignerList { port, authfile } => rpc_cli::signer_list(port, authfile).map(|s| PostExecutionAction::Print(s)),
Cmd::SignerList { port, authfile } => Cmd::SignerReject { id, port, authfile } => rpc_cli::signer_reject(id, port, authfile).map(|s| PostExecutionAction::Print(s)),
rpc_cli::cmd_signer_list(port, authfile), Cmd::Snapshot(snapshot_cmd) => snapshot::execute(snapshot_cmd).map(|s| PostExecutionAction::Print(s)),
Cmd::SignerReject { id, port, authfile } =>
rpc_cli::cmd_signer_reject(id, port, authfile),
Cmd::Snapshot(snapshot_cmd) => snapshot::execute(snapshot_cmd),
} }
} }
fn start() -> Result<String, String> { fn start(can_restart: bool) -> Result<PostExecutionAction, String> {
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
let conf = Configuration::parse(&args).unwrap_or_else(|e| e.exit()); let conf = Configuration::parse(&args).unwrap_or_else(|e| e.exit());
@ -169,61 +175,118 @@ fn start() -> Result<String, String> {
} }
let cmd = try!(conf.into_command()); let cmd = try!(conf.into_command());
execute(cmd) execute(cmd, can_restart)
}
#[cfg(feature="stratum")]
mod stratum_optional {
pub fn probably_run() -> bool {
// just redirect to the stratum::main()
if ::std::env::args().nth(1).map_or(false, |arg| arg == "stratum") {
super::stratum::main();
true
}
else { false }
}
} }
#[cfg(not(feature="stratum"))] #[cfg(not(feature="stratum"))]
mod stratum_optional { fn stratum_main(_: &mut HashMap<String, fn()>) {}
pub fn probably_run() -> bool {
false #[cfg(feature="stratum")]
} fn stratum_main(alt_mains: &mut HashMap<String, fn()>) {
alt_mains.insert("stratum".to_owned(), stratum::main);
} }
#[cfg(not(feature="ipc"))] #[cfg(not(feature="ipc"))]
fn sync_main() -> bool { fn sync_main(_: &mut HashMap<String, fn()>) {}
false
}
#[cfg(feature="ipc")] #[cfg(feature="ipc")]
fn sync_main() -> bool { fn sync_main(alt_mains: &mut HashMap<String, fn()>) {
// just redirect to the sync::main() alt_mains.insert("sync".to_owned(), sync::main);
if std::env::args().nth(1).map_or(false, |arg| arg == "sync") { }
sync::main();
true fn updates_path(name: &str) -> PathBuf {
let mut dest = PathBuf::from(default_hypervisor_path());
dest.push(name);
dest
}
fn latest_exe_path() -> Option<PathBuf> {
File::open(updates_path("latest")).ok()
.and_then(|mut f| { let mut exe = String::new(); f.read_to_string(&mut exe).ok().map(|_| updates_path(&exe)) })
}
// Starts ~/.parity-updates/parity and returns the code it exits with.
fn run_parity() -> Option<i32> {
use ::std::ffi::OsString;
let prefix = vec![OsString::from("--can-restart"), OsString::from("--force-direct")];
latest_exe_path().and_then(|exe| process::Command::new(exe)
.args(&(env::args_os().chain(prefix.into_iter()).collect::<Vec<_>>()))
.status()
.map(|es| es.code().unwrap_or(128))
.ok()
)
}
const PLEASE_RESTART_EXIT_CODE: i32 = 69;
// Run our version of parity.
// Returns the exit error code.
fn main_direct(can_restart: bool) -> i32 {
let mut alt_mains = HashMap::new();
sync_main(&mut alt_mains);
stratum_main(&mut alt_mains);
if let Some(f) = std::env::args().nth(1).and_then(|arg| alt_mains.get(&arg.to_string())) {
f();
0
} else { } else {
false match start(can_restart) {
Ok(result) => match result {
PostExecutionAction::Print(s) => { println!("{}", s); 0 },
PostExecutionAction::Restart => PLEASE_RESTART_EXIT_CODE,
PostExecutionAction::Quit => 0,
},
Err(err) => {
writeln!(&mut stdio::stderr(), "{}", err).expect("StdErr available; qed");
1
},
}
} }
} }
fn println_trace_main(s: String) {
if env::var("RUST_LOG").ok().and_then(|s| s.find("main=trace")).is_some() {
println!("{}", s);
}
}
#[macro_export]
macro_rules! trace_main {
($arg:expr) => (println_trace_main($arg.into()));
($($arg:tt)*) => (println_trace_main(format!("{}", format_args!($($arg)*))));
}
fn main() { fn main() {
// Always print backtrace on panic. // Always print backtrace on panic.
::std::env::set_var("RUST_BACKTRACE", "1"); env::set_var("RUST_BACKTRACE", "1");
if sync_main() { // assuming the user is not running with `--force-direct`, then:
return; // if argv[0] == "parity" and this executable != ~/.parity-updates/parity, run that instead.
} let force_direct = std::env::args().any(|arg| arg == "--force-direct");
let exe = std::env::current_exe().ok();
if stratum_optional::probably_run() { return; } let development = exe.as_ref().and_then(|p| p.parent().and_then(|p| p.parent()).and_then(|p| p.file_name()).map(|n| n == "target")).unwrap_or(false);
let same_name = exe.as_ref().map(|p| p.file_stem().map_or(false, |s| s == "parity") && p.extension().map_or(true, |x| x == "exe")).unwrap_or(false);
match start() { let latest_exe = latest_exe_path();
Ok(result) => { let have_update = latest_exe.as_ref().map_or(false, |p| p.exists());
info!("{}", result); let is_non_updated_current = exe.map_or(false, |exe| latest_exe.as_ref().map_or(false, |lexe| exe.canonicalize().ok() != lexe.canonicalize().ok()));
}, trace_main!("Starting up {} (force-direct: {}, development: {}, same-name: {}, have-update: {}, non-updated-current: {})", std::env::current_exe().map(|x| format!("{}", x.display())).unwrap_or("<unknown>".to_owned()), force_direct, development, same_name, have_update, is_non_updated_current);
Err(err) => { if !force_direct && !development && same_name && have_update && is_non_updated_current {
writeln!(&mut stdio::stderr(), "{}", err).expect("StdErr available; qed"); // looks like we're not running ~/.parity-updates/parity when the user is expecting otherwise.
process::exit(1); // Everything run inside a loop, so we'll be able to restart from the child into a new version seamlessly.
loop {
// If we fail to run the updated parity then fallback to local version.
trace_main!("Attempting to run latest update ({})...", latest_exe.as_ref().expect("guarded by have_update; latest_exe must exist for have_update; qed").display());
let exit_code = run_parity().unwrap_or_else(|| { trace_main!("Falling back to local..."); main_direct(true) });
trace_main!("Latest exited with {}", exit_code);
if exit_code != PLEASE_RESTART_EXIT_CODE {
trace_main!("Quitting...");
process::exit(exit_code);
}
trace_main!("Rerunning...");
} }
} else {
trace_main!("Running direct");
// Otherwise, we're presumably running the version we want. Just run and fall-through.
let can_restart = std::env::args().any(|arg| arg == "--can-restart");
process::exit(main_direct(can_restart));
} }
} }

View File

@ -27,7 +27,7 @@ use ethcore::snapshot::SnapshotService;
use ethsync::{ManageNetwork, SyncProvider}; use ethsync::{ManageNetwork, SyncProvider};
use ethcore_rpc::{Extendable, NetworkSettings}; use ethcore_rpc::{Extendable, NetworkSettings};
pub use ethcore_rpc::SignerService; pub use ethcore_rpc::SignerService;
use updater::Updater;
#[derive(Debug, PartialEq, Clone, Eq, Hash)] #[derive(Debug, PartialEq, Clone, Eq, Hash)]
pub enum Api { pub enum Api {
@ -118,6 +118,7 @@ pub struct Dependencies {
pub logger: Arc<RotatingLogger>, pub logger: Arc<RotatingLogger>,
pub settings: Arc<NetworkSettings>, pub settings: Arc<NetworkSettings>,
pub net_service: Arc<ManageNetwork>, pub net_service: Arc<ManageNetwork>,
pub updater: Arc<Updater>,
pub geth_compatibility: bool, pub geth_compatibility: bool,
pub dapps_interface: Option<String>, pub dapps_interface: Option<String>,
pub dapps_port: Option<u16>, pub dapps_port: Option<u16>,
@ -224,6 +225,7 @@ pub fn setup_rpc<T: Extendable>(server: T, deps: Arc<Dependencies>, apis: ApiSet
&deps.client, &deps.client,
&deps.miner, &deps.miner,
&deps.sync, &deps.sync,
&deps.updater,
&deps.net_service, &deps.net_service,
&deps.secret_store, &deps.secret_store,
deps.logger.clone(), deps.logger.clone(),
@ -240,7 +242,7 @@ pub fn setup_rpc<T: Extendable>(server: T, deps: Arc<Dependencies>, apis: ApiSet
server.add_delegate(ParityAccountsClient::new(&deps.secret_store, &deps.client).to_delegate()); server.add_delegate(ParityAccountsClient::new(&deps.secret_store, &deps.client).to_delegate());
}, },
Api::ParitySet => { Api::ParitySet => {
server.add_delegate(ParitySetClient::new(&deps.client, &deps.miner, &deps.net_service).to_delegate()) server.add_delegate(ParitySetClient::new(&deps.client, &deps.miner, &deps.updater, &deps.net_service).to_delegate())
}, },
Api::Traces => { Api::Traces => {
server.add_delegate(TracesClient::new(&deps.client, &deps.miner).to_delegate()) server.add_delegate(TracesClient::new(&deps.client, &deps.miner).to_delegate())

View File

@ -14,16 +14,16 @@
// 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::sync::{Arc, Mutex, Condvar}; use std::sync::Arc;
use std::net::{TcpListener}; use std::net::{TcpListener};
use ctrlc::CtrlC; use ctrlc::CtrlC;
use fdlimit::raise_fd_limit; use fdlimit::raise_fd_limit;
use ethcore_rpc::{NetworkSettings, is_major_importing}; use ethcore_rpc::{NetworkSettings, is_major_importing};
use ethsync::NetworkConfiguration; use ethsync::NetworkConfiguration;
use util::{Colour, version, RotatingLogger}; use util::{Colour, version, RotatingLogger, Mutex, Condvar};
use io::{MayPanic, ForwardPanic, PanicHandler}; use io::{MayPanic, ForwardPanic, PanicHandler};
use ethcore_logger::{Config as LogConfig}; use ethcore_logger::{Config as LogConfig};
use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, ChainNotify, BlockChainClient}; use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, BlockChainClient};
use ethcore::service::ClientService; use ethcore::service::ClientService;
use ethcore::account_provider::AccountProvider; use ethcore::account_provider::AccountProvider;
use ethcore::miner::{Miner, MinerService, ExternalMiner, MinerOptions}; use ethcore::miner::{Miner, MinerService, ExternalMiner, MinerOptions};
@ -31,11 +31,11 @@ use ethcore::snapshot;
use ethcore::verification::queue::VerifierSettings; use ethcore::verification::queue::VerifierSettings;
use ethsync::SyncConfig; use ethsync::SyncConfig;
use informant::Informant; use informant::Informant;
use updater::{UpdatePolicy, Updater};
use rpc::{HttpServer, IpcServer, HttpConfiguration, IpcConfiguration}; use rpc::{HttpServer, IpcServer, HttpConfiguration, IpcConfiguration};
use signer::SignerServer; use signer::SignerServer;
use dapps::WebappServer; use dapps::WebappServer;
use io_handler::ClientIoHandler;
use params::{ use params::{
SpecType, Pruning, AccountsConfig, GasPricerConfig, MinerExtras, Switch, SpecType, Pruning, AccountsConfig, GasPricerConfig, MinerExtras, Switch,
tracing_switch_to_bool, fatdb_switch_to_bool, mode_switch_to_bool tracing_switch_to_bool, fatdb_switch_to_bool, mode_switch_to_bool
@ -77,6 +77,7 @@ pub struct RunCmd {
pub acc_conf: AccountsConfig, pub acc_conf: AccountsConfig,
pub gas_pricer: GasPricerConfig, pub gas_pricer: GasPricerConfig,
pub miner_extras: MinerExtras, pub miner_extras: MinerExtras,
pub update_policy: UpdatePolicy,
pub mode: Option<Mode>, pub mode: Option<Mode>,
pub tracing: Switch, pub tracing: Switch,
pub fat_db: Switch, pub fat_db: Switch,
@ -115,12 +116,12 @@ pub fn open_ui(dapps_conf: &dapps::Configuration, signer_conf: &signer::Configur
Ok(()) Ok(())
} }
pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<(), String> { pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> Result<bool, String> {
if cmd.ui && cmd.dapps_conf.enabled { if cmd.ui && cmd.dapps_conf.enabled {
// Check if Parity is already running // Check if Parity is already running
let addr = format!("{}:{}", cmd.dapps_conf.interface, cmd.dapps_conf.port); let addr = format!("{}:{}", cmd.dapps_conf.interface, cmd.dapps_conf.port);
if !TcpListener::bind(&addr as &str).is_ok() { if !TcpListener::bind(&addr as &str).is_ok() {
return open_ui(&cmd.dapps_conf, &cmd.signer_conf); return open_ui(&cmd.dapps_conf, &cmd.signer_conf).map(|_| false);
} }
} }
@ -159,6 +160,9 @@ pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<(), String> {
trace!(target: "mode", "mode is {:?}", mode); trace!(target: "mode", "mode is {:?}", mode);
let network_enabled = match mode { Mode::Dark(_) | Mode::Off => false, _ => true, }; let network_enabled = match mode { Mode::Dark(_) | Mode::Off => false, _ => true, };
// get the update policy
let update_policy = cmd.update_policy;
// prepare client and snapshot paths. // prepare client and snapshot paths.
let client_path = db_dirs.client_path(algorithm); let client_path = db_dirs.client_path(algorithm);
let snapshot_path = db_dirs.snapshot_path(); let snapshot_path = db_dirs.snapshot_path();
@ -307,6 +311,10 @@ pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<(), String> {
chain_notify.start(); chain_notify.start();
} }
// the updater service
let updater = Updater::new(Arc::downgrade(&(service.client() as Arc<BlockChainClient>)), Arc::downgrade(&sync_provider), update_policy);
service.add_notify(updater.clone());
// set up dependencies for rpc servers // set up dependencies for rpc servers
let signer_path = cmd.signer_conf.signer_path.clone(); let signer_path = cmd.signer_conf.signer_path.clone();
let deps_for_rpc_apis = Arc::new(rpc_apis::Dependencies { let deps_for_rpc_apis = Arc::new(rpc_apis::Dependencies {
@ -323,6 +331,7 @@ pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<(), String> {
logger: logger.clone(), logger: logger.clone(),
settings: Arc::new(cmd.net_settings.clone()), settings: Arc::new(cmd.net_settings.clone()),
net_service: manage_network.clone(), net_service: manage_network.clone(),
updater: updater.clone(),
geth_compatibility: cmd.geth_compatibility, geth_compatibility: cmd.geth_compatibility,
dapps_interface: match cmd.dapps_conf.enabled { dapps_interface: match cmd.dapps_conf.enabled {
true => Some(cmd.dapps_conf.interface.clone()), true => Some(cmd.dapps_conf.interface.clone()),
@ -343,24 +352,23 @@ pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<(), String> {
let http_server = try!(rpc::new_http(cmd.http_conf, &dependencies)); let http_server = try!(rpc::new_http(cmd.http_conf, &dependencies));
let ipc_server = try!(rpc::new_ipc(cmd.ipc_conf, &dependencies)); let ipc_server = try!(rpc::new_ipc(cmd.ipc_conf, &dependencies));
// the dapps server
let dapps_deps = dapps::Dependencies { let dapps_deps = dapps::Dependencies {
panic_handler: panic_handler.clone(), panic_handler: panic_handler.clone(),
apis: deps_for_rpc_apis.clone(), apis: deps_for_rpc_apis.clone(),
client: client.clone(), client: client.clone(),
sync: sync_provider.clone(), sync: sync_provider.clone(),
}; };
// start dapps server
let dapps_server = try!(dapps::new(cmd.dapps_conf.clone(), dapps_deps)); let dapps_server = try!(dapps::new(cmd.dapps_conf.clone(), dapps_deps));
// the signer server
let signer_deps = signer::Dependencies { let signer_deps = signer::Dependencies {
panic_handler: panic_handler.clone(), panic_handler: panic_handler.clone(),
apis: deps_for_rpc_apis.clone(), apis: deps_for_rpc_apis.clone(),
}; };
// start signer server
let signer_server = try!(signer::start(cmd.signer_conf.clone(), signer_deps)); let signer_server = try!(signer::start(cmd.signer_conf.clone(), signer_deps));
// the informant
let informant = Arc::new(Informant::new( let informant = Arc::new(Informant::new(
service.client(), service.client(),
Some(sync_provider.clone()), Some(sync_provider.clone()),
@ -368,17 +376,8 @@ pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<(), String> {
Some(snapshot_service.clone()), Some(snapshot_service.clone()),
cmd.logger_config.color cmd.logger_config.color
)); ));
let info_notify: Arc<ChainNotify> = informant.clone(); service.add_notify(informant.clone());
service.add_notify(info_notify); service.register_io_handler(informant.clone()).map_err(|_| "Unable to register informant handler".to_owned())?;
let io_handler = Arc::new(ClientIoHandler {
client: service.client(),
info: informant,
sync: sync_provider.clone(),
net: manage_network.clone(),
accounts: account_provider.clone(),
shutdown: Default::default(),
});
service.register_io_handler(io_handler.clone()).expect("Error registering IO handler");
// save user defaults // save user defaults
user_defaults.pruning = algorithm; user_defaults.pruning = algorithm;
@ -387,13 +386,11 @@ pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<(), String> {
user_defaults.mode = mode; user_defaults.mode = mode;
try!(user_defaults.save(&user_defaults_path)); try!(user_defaults.save(&user_defaults_path));
let on_mode_change = move |mode: &Mode| { // tell client how to save the default mode if it gets changed.
client.on_mode_change(move |mode: &Mode| {
user_defaults.mode = mode.clone(); user_defaults.mode = mode.clone();
let _ = user_defaults.save(&user_defaults_path); // discard failures - there's nothing we can do let _ = user_defaults.save(&user_defaults_path); // discard failures - there's nothing we can do
}; });
// tell client how to save the default mode if it gets changed.
client.on_mode_change(on_mode_change);
// the watcher must be kept alive. // the watcher must be kept alive.
let _watcher = match cmd.no_periodic_snapshot { let _watcher = match cmd.no_periodic_snapshot {
@ -419,18 +416,20 @@ pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<(), String> {
} }
// Handle exit // Handle exit
wait_for_exit(panic_handler, http_server, ipc_server, dapps_server, signer_server); let restart = wait_for_exit(panic_handler, http_server, ipc_server, dapps_server, signer_server, updater, can_restart);
info!("Finishing work, please wait...");
// to make sure timer does not spawn requests while shutdown is in progress // to make sure timer does not spawn requests while shutdown is in progress
io_handler.shutdown.store(true, ::std::sync::atomic::Ordering::SeqCst); informant.shutdown();
// just Arc is dropping here, to allow other reference release in its default time // just Arc is dropping here, to allow other reference release in its default time
drop(io_handler); drop(informant);
// hypervisor should be shutdown first while everything still works and can be // hypervisor should be shutdown first while everything still works and can be
// terminated gracefully // terminated gracefully
drop(hypervisor); drop(hypervisor);
Ok(()) Ok(restart)
} }
#[cfg(not(windows))] #[cfg(not(windows))]
@ -438,11 +437,11 @@ fn daemonize(pid_file: String) -> Result<(), String> {
extern crate daemonize; extern crate daemonize;
daemonize::Daemonize::new() daemonize::Daemonize::new()
.pid_file(pid_file) .pid_file(pid_file)
.chown_pid_file(true) .chown_pid_file(true)
.start() .start()
.map(|_| ()) .map(|_| ())
.map_err(|e| format!("Couldn't daemonize; {}", e)) .map_err(|e| format!("Couldn't daemonize; {}", e))
} }
#[cfg(windows)] #[cfg(windows)]
@ -475,20 +474,30 @@ fn wait_for_exit(
_http_server: Option<HttpServer>, _http_server: Option<HttpServer>,
_ipc_server: Option<IpcServer>, _ipc_server: Option<IpcServer>,
_dapps_server: Option<WebappServer>, _dapps_server: Option<WebappServer>,
_signer_server: Option<SignerServer> _signer_server: Option<SignerServer>,
) { updater: Arc<Updater>,
let exit = Arc::new(Condvar::new()); can_restart: bool
) -> bool {
let exit = Arc::new((Mutex::new(false), Condvar::new()));
// Handle possible exits // Handle possible exits
let e = exit.clone(); let e = exit.clone();
CtrlC::set_handler(move || { e.notify_all(); }); CtrlC::set_handler(move || { e.1.notify_all(); });
// Handle panics // Handle panics
let e = exit.clone(); let e = exit.clone();
panic_handler.on_panic(move |_reason| { e.notify_all(); }); panic_handler.on_panic(move |_reason| { e.1.notify_all(); });
// Handle updater wanting to restart us
if can_restart {
let e = exit.clone();
updater.set_exit_handler(move || { *e.0.lock() = true; e.1.notify_all(); });
} else {
updater.set_exit_handler(|| info!("Update installed; ready for restart."));
}
// Wait for signal // Wait for signal
let mutex = Mutex::new(()); let mut l = exit.0.lock();
let _ = exit.wait(mutex.lock().unwrap()); let _ = exit.1.wait(&mut l);
info!("Finishing work, please wait..."); *l
} }

View File

@ -26,6 +26,7 @@ ethash = { path = "../ethash" }
ethsync = { path = "../sync" } ethsync = { path = "../sync" }
ethjson = { path = "../json" } ethjson = { path = "../json" }
ethcore-devtools = { path = "../devtools" } ethcore-devtools = { path = "../devtools" }
parity-updater = { path = "../updater" }
rlp = { path = "../util/rlp" } rlp = { path = "../util/rlp" }
fetch = { path = "../util/fetch" } fetch = { path = "../util/fetch" }
rustc-serialize = "0.3" rustc-serialize = "0.3"
@ -34,6 +35,7 @@ serde_macros = { version = "0.8.0", optional = true }
clippy = { version = "0.0.103", optional = true} clippy = { version = "0.0.103", optional = true}
ethcore-ipc = { path = "../ipc/rpc" } ethcore-ipc = { path = "../ipc/rpc" }
time = "0.1" time = "0.1"
semver = "0.5"
[build-dependencies] [build-dependencies]
serde_codegen = { version = "0.8.0", optional = true } serde_codegen = { version = "0.8.0", optional = true }

View File

@ -19,6 +19,7 @@
#![cfg_attr(feature="nightly", feature(custom_derive, custom_attribute, plugin))] #![cfg_attr(feature="nightly", feature(custom_derive, custom_attribute, plugin))]
#![cfg_attr(feature="nightly", plugin(serde_macros, clippy))] #![cfg_attr(feature="nightly", plugin(serde_macros, clippy))]
extern crate semver;
extern crate rustc_serialize; extern crate rustc_serialize;
extern crate serde; extern crate serde;
extern crate serde_json; extern crate serde_json;
@ -37,6 +38,7 @@ extern crate ethcore_ipc;
extern crate time; extern crate time;
extern crate rlp; extern crate rlp;
extern crate fetch; extern crate fetch;
extern crate parity_updater as updater;
#[macro_use] #[macro_use]
extern crate log; extern crate log;

View File

@ -30,6 +30,7 @@ use ethcore::miner::MinerService;
use ethcore::client::{MiningBlockChainClient}; use ethcore::client::{MiningBlockChainClient};
use ethcore::mode::Mode; use ethcore::mode::Mode;
use ethcore::account_provider::AccountProvider; use ethcore::account_provider::AccountProvider;
use updater::{Service as UpdateService};
use jsonrpc_core::Error; use jsonrpc_core::Error;
use jsonrpc_macros::Trailing; use jsonrpc_macros::Trailing;
@ -38,20 +39,23 @@ use v1::types::{
Bytes, U256, H160, H256, H512, Bytes, U256, H160, H256, H512,
Peers, Transaction, RpcSettings, Histogram, Peers, Transaction, RpcSettings, Histogram,
TransactionStats, LocalTransactionStatus, TransactionStats, LocalTransactionStatus,
BlockNumber, BlockNumber, ConsensusCapability, VersionInfo,
OperationsInfo
}; };
use v1::helpers::{errors, SigningQueue, SignerService, NetworkSettings}; use v1::helpers::{errors, SigningQueue, SignerService, NetworkSettings};
use v1::helpers::dispatch::DEFAULT_MAC; use v1::helpers::dispatch::DEFAULT_MAC;
/// Parity implementation. /// Parity implementation.
pub struct ParityClient<C, M, S: ?Sized> where pub struct ParityClient<C, M, S: ?Sized, U> where
C: MiningBlockChainClient, C: MiningBlockChainClient,
M: MinerService, M: MinerService,
S: SyncProvider, S: SyncProvider,
U: UpdateService,
{ {
client: Weak<C>, client: Weak<C>,
miner: Weak<M>, miner: Weak<M>,
sync: Weak<S>, sync: Weak<S>,
updater: Weak<U>,
net: Weak<ManageNetwork>, net: Weak<ManageNetwork>,
accounts: Weak<AccountProvider>, accounts: Weak<AccountProvider>,
logger: Arc<RotatingLogger>, logger: Arc<RotatingLogger>,
@ -61,16 +65,18 @@ pub struct ParityClient<C, M, S: ?Sized> where
dapps_port: Option<u16>, dapps_port: Option<u16>,
} }
impl<C, M, S: ?Sized> ParityClient<C, M, S> where impl<C, M, S: ?Sized, U> ParityClient<C, M, S, U> where
C: MiningBlockChainClient, C: MiningBlockChainClient,
M: MinerService, M: MinerService,
S: SyncProvider, S: SyncProvider,
U: UpdateService,
{ {
/// Creates new `ParityClient`. /// Creates new `ParityClient`.
pub fn new( pub fn new(
client: &Arc<C>, client: &Arc<C>,
miner: &Arc<M>, miner: &Arc<M>,
sync: &Arc<S>, sync: &Arc<S>,
updater: &Arc<U>,
net: &Arc<ManageNetwork>, net: &Arc<ManageNetwork>,
store: &Arc<AccountProvider>, store: &Arc<AccountProvider>,
logger: Arc<RotatingLogger>, logger: Arc<RotatingLogger>,
@ -83,6 +89,7 @@ impl<C, M, S: ?Sized> ParityClient<C, M, S> where
client: Arc::downgrade(client), client: Arc::downgrade(client),
miner: Arc::downgrade(miner), miner: Arc::downgrade(miner),
sync: Arc::downgrade(sync), sync: Arc::downgrade(sync),
updater: Arc::downgrade(updater),
net: Arc::downgrade(net), net: Arc::downgrade(net),
accounts: Arc::downgrade(store), accounts: Arc::downgrade(store),
logger: logger, logger: logger,
@ -100,10 +107,11 @@ impl<C, M, S: ?Sized> ParityClient<C, M, S> where
} }
} }
impl<C, M, S: ?Sized> Parity for ParityClient<C, M, S> where impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
M: MinerService + 'static, M: MinerService + 'static,
C: MiningBlockChainClient + 'static, C: MiningBlockChainClient + 'static,
S: SyncProvider + 'static { S: SyncProvider + 'static,
U: UpdateService + 'static {
fn transactions_limit(&self) -> Result<usize, Error> { fn transactions_limit(&self) -> Result<usize, Error> {
try!(self.active()); try!(self.active());
@ -353,4 +361,22 @@ impl<C, M, S: ?Sized> Parity for ParityClient<C, M, S> where
(format!("0x{}", a.hex()), m) (format!("0x{}", a.hex()), m)
}).collect()) }).collect())
} }
fn consensus_capability(&self) -> Result<ConsensusCapability, Error> {
try!(self.active());
let updater = take_weak!(self.updater);
Ok(updater.capability().into())
}
fn version_info(&self) -> Result<VersionInfo, Error> {
try!(self.active());
let updater = take_weak!(self.updater);
Ok(updater.version_info().into())
}
fn releases_info(&self) -> Result<Option<OperationsInfo>, Error> {
try!(self.active());
let updater = take_weak!(self.updater);
Ok(updater.info().map(Into::into))
}
} }

View File

@ -24,45 +24,51 @@ use ethcore::mode::Mode;
use ethsync::ManageNetwork; use ethsync::ManageNetwork;
use fetch::{Client as FetchClient, Fetch}; use fetch::{Client as FetchClient, Fetch};
use util::{Mutex, sha3}; use util::{Mutex, sha3};
use updater::{Service as UpdateService};
use jsonrpc_core::Error; use jsonrpc_core::Error;
use jsonrpc_macros::Ready; use jsonrpc_macros::Ready;
use v1::helpers::errors; use v1::helpers::errors;
use v1::traits::ParitySet; use v1::traits::ParitySet;
use v1::types::{Bytes, H160, H256, U256}; use v1::types::{Bytes, H160, H256, U256, ReleaseInfo};
/// Parity-specific rpc interface for operations altering the settings. /// Parity-specific rpc interface for operations altering the settings.
pub struct ParitySetClient<C, M, F=FetchClient> where pub struct ParitySetClient<C, M, U, F=FetchClient> where
C: MiningBlockChainClient, C: MiningBlockChainClient,
M: MinerService, M: MinerService,
U: UpdateService,
F: Fetch, F: Fetch,
{ {
client: Weak<C>, client: Weak<C>,
miner: Weak<M>, miner: Weak<M>,
updater: Weak<U>,
net: Weak<ManageNetwork>, net: Weak<ManageNetwork>,
fetch: Mutex<F>, fetch: Mutex<F>,
} }
impl<C, M> ParitySetClient<C, M, FetchClient> where impl<C, M, U> ParitySetClient<C, M, U, FetchClient> where
C: MiningBlockChainClient, C: MiningBlockChainClient,
M: MinerService M: MinerService,
U: UpdateService,
{ {
/// Creates new `ParitySetClient` with default `FetchClient`. /// Creates new `ParitySetClient` with default `FetchClient`.
pub fn new(client: &Arc<C>, miner: &Arc<M>, net: &Arc<ManageNetwork>) -> Self { pub fn new(client: &Arc<C>, miner: &Arc<M>, updater: &Arc<U>, net: &Arc<ManageNetwork>) -> Self {
Self::with_fetch(client, miner, net) Self::with_fetch(client, miner, updater, net)
} }
} }
impl<C, M, F> ParitySetClient<C, M, F> where impl<C, M, U, F> ParitySetClient<C, M, U, F> where
C: MiningBlockChainClient, C: MiningBlockChainClient,
M: MinerService, M: MinerService,
U: UpdateService,
F: Fetch, F: Fetch,
{ {
/// Creates new `ParitySetClient` with default `FetchClient`. /// Creates new `ParitySetClient` with default `FetchClient`.
pub fn with_fetch(client: &Arc<C>, miner: &Arc<M>, net: &Arc<ManageNetwork>) -> Self { pub fn with_fetch(client: &Arc<C>, miner: &Arc<M>, updater: &Arc<U>, net: &Arc<ManageNetwork>) -> Self {
ParitySetClient { ParitySetClient {
client: Arc::downgrade(client), client: Arc::downgrade(client),
miner: Arc::downgrade(miner), miner: Arc::downgrade(miner),
updater: Arc::downgrade(updater),
net: Arc::downgrade(net), net: Arc::downgrade(net),
fetch: Mutex::new(F::default()), fetch: Mutex::new(F::default()),
} }
@ -75,9 +81,10 @@ impl<C, M, F> ParitySetClient<C, M, F> where
} }
} }
impl<C, M, F> ParitySet for ParitySetClient<C, M, F> where impl<C, M, U, F> ParitySet for ParitySetClient<C, M, U, F> where
C: MiningBlockChainClient + 'static, C: MiningBlockChainClient + 'static,
M: MinerService + 'static, M: MinerService + 'static,
U: UpdateService + 'static,
F: Fetch + 'static, F: Fetch + 'static,
{ {
@ -230,4 +237,16 @@ impl<C, M, F> ParitySet for ParitySetClient<C, M, F> where
} }
} }
} }
fn upgrade_ready(&self) -> Result<Option<ReleaseInfo>, Error> {
try!(self.active());
let updater = take_weak!(self.updater);
Ok(updater.upgrade_ready().map(Into::into))
}
fn execute_upgrade(&self) -> Result<bool, Error> {
try!(self.active());
let updater = take_weak!(self.updater);
Ok(updater.execute_upgrade())
}
} }

View File

@ -20,8 +20,10 @@ mod sync_provider;
mod miner_service; mod miner_service;
mod fetch; mod fetch;
mod snapshot_service; mod snapshot_service;
mod update_service;
pub use self::sync_provider::{Config, TestSyncProvider}; pub use self::sync_provider::{Config, TestSyncProvider};
pub use self::miner_service::TestMinerService; pub use self::miner_service::TestMinerService;
pub use self::fetch::TestFetch; pub use self::fetch::TestFetch;
pub use self::snapshot_service::TestSnapshotService; pub use self::snapshot_service::TestSnapshotService;
pub use self::update_service::TestUpdater;

View File

@ -0,0 +1,97 @@
// 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/>.
//! Test implementation of fetch client.
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use semver::Version;
use updater::{Service as UpdateService, CapState, ReleaseInfo, VersionInfo, OperationsInfo, ReleaseTrack};
/// Test implementation of fetcher. Will always return the same file.
#[derive(Default)]
pub struct TestUpdater {
updated: AtomicBool,
current_block: AtomicUsize,
}
impl TestUpdater {
/// Update the (faked) current block.
pub fn set_current_block(&self, n: usize) {
self.current_block.store(n, Ordering::Relaxed);
}
/// Update the (faked) current block.
pub fn set_updated(&self, v: bool) {
self.updated.store(v, Ordering::Relaxed);
}
}
impl UpdateService for TestUpdater {
fn capability(&self) -> CapState {
if self.updated.load(Ordering::Relaxed) {
CapState::Capable
} else {
if self.current_block.load(Ordering::Relaxed) < 15100 {
CapState::CapableUntil(15100)
} else {
CapState::IncapableSince(15100)
}
}
}
fn upgrade_ready(&self) -> Option<ReleaseInfo> {
if self.updated.load(Ordering::Relaxed) {
None
} else {
self.info().map(|i| i.track)
}
}
fn execute_upgrade(&self) -> bool {
if self.updated.load(Ordering::Relaxed) {
false
} else {
self.updated.store(true, Ordering::Relaxed);
true
}
}
fn version_info(&self) -> VersionInfo {
VersionInfo {
track: ReleaseTrack::Beta,
version: Version{major: 1, minor: 5, patch: 0, build: vec![], pre: vec![]},
hash: 150.into(),
}
}
fn info(&self) -> Option<OperationsInfo> {
Some(OperationsInfo {
fork: 15100,
this_fork: Some(15000),
track: ReleaseInfo {
version: VersionInfo {
track: ReleaseTrack::Beta,
version: Version{major: 1, minor: 5, patch: 1, build: vec![], pre: vec![]},
hash: 151.into(),
},
is_critical: true,
fork: 15100,
binary: Some(1510.into()),
},
minor: None,
})
}
}

View File

@ -26,15 +26,16 @@ use ethstore::ethkey::{Generator, Random};
use jsonrpc_core::{IoHandler, GenericIoHandler}; use jsonrpc_core::{IoHandler, GenericIoHandler};
use v1::{Parity, ParityClient}; use v1::{Parity, ParityClient};
use v1::helpers::{SignerService, NetworkSettings}; use v1::helpers::{SignerService, NetworkSettings};
use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService}; use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService, TestUpdater};
use super::manage_network::TestManageNetwork; use super::manage_network::TestManageNetwork;
pub type TestParityClient = ParityClient<TestBlockChainClient, TestMinerService, TestSyncProvider>; pub type TestParityClient = ParityClient<TestBlockChainClient, TestMinerService, TestSyncProvider, TestUpdater>;
pub struct Dependencies { pub struct Dependencies {
pub miner: Arc<TestMinerService>, pub miner: Arc<TestMinerService>,
pub client: Arc<TestBlockChainClient>, pub client: Arc<TestBlockChainClient>,
pub sync: Arc<TestSyncProvider>, pub sync: Arc<TestSyncProvider>,
pub updater: Arc<TestUpdater>,
pub logger: Arc<RotatingLogger>, pub logger: Arc<RotatingLogger>,
pub settings: Arc<NetworkSettings>, pub settings: Arc<NetworkSettings>,
pub network: Arc<ManageNetwork>, pub network: Arc<ManageNetwork>,
@ -52,6 +53,7 @@ impl Dependencies {
network_id: 3, network_id: 3,
num_peers: 120, num_peers: 120,
})), })),
updater: Arc::new(TestUpdater::default()),
logger: Arc::new(RotatingLogger::new("rpc=trace".to_owned())), logger: Arc::new(RotatingLogger::new("rpc=trace".to_owned())),
settings: Arc::new(NetworkSettings { settings: Arc::new(NetworkSettings {
name: "mynode".to_owned(), name: "mynode".to_owned(),
@ -73,6 +75,7 @@ impl Dependencies {
&self.client, &self.client,
&self.miner, &self.miner,
&self.sync, &self.sync,
&self.updater,
&self.network, &self.network,
&self.accounts, &self.accounts,
self.logger.clone(), self.logger.clone(),
@ -96,6 +99,48 @@ impl Dependencies {
} }
} }
#[test]
fn rpc_parity_consensus_capability() {
let deps = Dependencies::new();
let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "parity_consensusCapability", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":{"capableUntil":15100},"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
deps.updater.set_current_block(15101);
let request = r#"{"jsonrpc": "2.0", "method": "parity_consensusCapability", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":{"incapableSince":15100},"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
deps.updater.set_updated(true);
let request = r#"{"jsonrpc": "2.0", "method": "parity_consensusCapability", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"capable","id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_parity_version_info() {
let deps = Dependencies::new();
let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "parity_versionInfo", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":{"hash":"0x0000000000000000000000000000000000000096","track":"beta","version":{"major":1,"minor":5,"patch":0}},"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_parity_releases_info() {
let deps = Dependencies::new();
let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "parity_releasesInfo", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":{"fork":15100,"minor":null,"this_fork":15000,"track":{"binary":"0x00000000000000000000000000000000000000000000000000000000000005e6","fork":15100,"is_critical":true,"version":{"hash":"0x0000000000000000000000000000000000000097","track":"beta","version":{"major":1,"minor":5,"patch":1}}}},"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}
#[test] #[test]
fn rpc_parity_extra_data() { fn rpc_parity_extra_data() {
let deps = Dependencies::new(); let deps = Dependencies::new();
@ -196,12 +241,7 @@ fn rpc_parity_net_peers() {
let io = deps.default_client(); let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "parity_netPeers", "params":[], "id": 1}"#; let request = r#"{"jsonrpc": "2.0", "method": "parity_netPeers", "params":[], "id": 1}"#;
let response = "{\"jsonrpc\":\"2.0\",\"result\":{\"active\":0,\"connected\":120,\"max\":50,\"peers\":[{\"caps\":[\"eth/62\",\"eth/63\"],\ let response = r#"{"jsonrpc":"2.0","result":{"active":0,"connected":120,"max":50,"peers":[{"caps":["eth/62","eth/63"],"id":"node1","name":"Parity/1","network":{"localAddress":"127.0.0.1:8888","remoteAddress":"127.0.0.1:7777"},"protocols":{"eth":{"difficulty":"0x28","head":"0000000000000000000000000000000000000000000000000000000000000032","version":62}}},{"caps":["eth/63","eth/64"],"id":null,"name":"Parity/2","network":{"localAddress":"127.0.0.1:3333","remoteAddress":"Handshake"},"protocols":{"eth":{"difficulty":null,"head":"000000000000000000000000000000000000000000000000000000000000003c","version":64}}}]},"id":1}"#;
\"id\":\"node1\",\"name\":\"Parity/1\",\"network\":{\"localAddress\":\"127.0.0.1:8888\",\"remoteAddress\":\"127.0.0.1:7777\"}\
,\"protocols\":{\"eth\":{\"difficulty\":\"0x28\",\"head\":\"0000000000000000000000000000000000000000000000000000000000000032\"\
,\"version\":62}}},{\"caps\":[\"eth/63\",\"eth/64\"],\"id\":null,\"name\":\"Parity/2\",\"network\":{\"localAddress\":\
\"127.0.0.1:3333\",\"remoteAddress\":\"Handshake\"},\"protocols\":{\"eth\":{\"difficulty\":null,\"head\":\
\"000000000000000000000000000000000000000000000000000000000000003c\",\"version\":64}}}]},\"id\":1}";
assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
} }

View File

@ -25,7 +25,7 @@ use ethsync::ManageNetwork;
use jsonrpc_core::{IoHandler, GenericIoHandler}; use jsonrpc_core::{IoHandler, GenericIoHandler};
use v1::{ParitySet, ParitySetClient}; use v1::{ParitySet, ParitySetClient};
use v1::tests::helpers::{TestMinerService, TestFetch}; use v1::tests::helpers::{TestMinerService, TestFetch, TestUpdater};
use super::manage_network::TestManageNetwork; use super::manage_network::TestManageNetwork;
fn miner_service() -> Arc<TestMinerService> { fn miner_service() -> Arc<TestMinerService> {
@ -40,10 +40,52 @@ fn network_service() -> Arc<TestManageNetwork> {
Arc::new(TestManageNetwork) Arc::new(TestManageNetwork)
} }
pub type TestParitySetClient = ParitySetClient<TestBlockChainClient, TestMinerService, TestFetch>; fn updater_service() -> Arc<TestUpdater> {
Arc::new(TestUpdater::default())
}
fn parity_set_client(client: &Arc<TestBlockChainClient>, miner: &Arc<TestMinerService>, net: &Arc<TestManageNetwork>) -> TestParitySetClient { pub type TestParitySetClient = ParitySetClient<TestBlockChainClient, TestMinerService, TestUpdater, TestFetch>;
ParitySetClient::with_fetch(client, miner, &(net.clone() as Arc<ManageNetwork>))
fn parity_set_client(client: &Arc<TestBlockChainClient>, miner: &Arc<TestMinerService>, updater: &Arc<TestUpdater>, net: &Arc<TestManageNetwork>) -> TestParitySetClient {
ParitySetClient::with_fetch(client, miner, updater, &(net.clone() as Arc<ManageNetwork>))
}
#[test]
fn rpc_parity_execute_upgrade() {
let miner = miner_service();
let client = client_service();
let network = network_service();
let updater = updater_service();
let io = IoHandler::new();
io.add_delegate(parity_set_client(&client, &miner, &updater, &network).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "parity_executeUpgrade", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
let request = r#"{"jsonrpc": "2.0", "method": "parity_executeUpgrade", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":false,"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_parity_upgrade_ready() {
let miner = miner_service();
let client = client_service();
let network = network_service();
let updater = updater_service();
let io = IoHandler::new();
io.add_delegate(parity_set_client(&client, &miner, &updater, &network).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "parity_upgradeReady", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":{"binary":"0x00000000000000000000000000000000000000000000000000000000000005e6","fork":15100,"is_critical":true,"version":{"hash":"0x0000000000000000000000000000000000000097","track":"beta","version":{"major":1,"minor":5,"patch":1}}},"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
updater.set_updated(true);
let request = r#"{"jsonrpc": "2.0", "method": "parity_upgradeReady", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":null,"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
} }
#[test] #[test]
@ -51,8 +93,9 @@ fn rpc_parity_set_min_gas_price() {
let miner = miner_service(); let miner = miner_service();
let client = client_service(); let client = client_service();
let network = network_service(); let network = network_service();
let updater = updater_service();
let io = IoHandler::new(); let io = IoHandler::new();
io.add_delegate(parity_set_client(&client, &miner, &network).to_delegate()); io.add_delegate(parity_set_client(&client, &miner, &updater, &network).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "parity_setMinGasPrice", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#; let request = r#"{"jsonrpc": "2.0", "method": "parity_setMinGasPrice", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
@ -66,8 +109,9 @@ fn rpc_parity_set_gas_floor_target() {
let miner = miner_service(); let miner = miner_service();
let client = client_service(); let client = client_service();
let network = network_service(); let network = network_service();
let updater = updater_service();
let io = IoHandler::new(); let io = IoHandler::new();
io.add_delegate(parity_set_client(&client, &miner, &network).to_delegate()); io.add_delegate(parity_set_client(&client, &miner, &updater, &network).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "parity_setGasFloorTarget", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#; let request = r#"{"jsonrpc": "2.0", "method": "parity_setGasFloorTarget", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
@ -81,8 +125,9 @@ fn rpc_parity_set_extra_data() {
let miner = miner_service(); let miner = miner_service();
let client = client_service(); let client = client_service();
let network = network_service(); let network = network_service();
let updater = updater_service();
let io = IoHandler::new(); let io = IoHandler::new();
io.add_delegate(parity_set_client(&client, &miner, &network).to_delegate()); io.add_delegate(parity_set_client(&client, &miner, &updater, &network).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "parity_setExtraData", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#; let request = r#"{"jsonrpc": "2.0", "method": "parity_setExtraData", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
@ -96,8 +141,9 @@ fn rpc_parity_set_author() {
let miner = miner_service(); let miner = miner_service();
let client = client_service(); let client = client_service();
let network = network_service(); let network = network_service();
let updater = updater_service();
let io = IoHandler::new(); let io = IoHandler::new();
io.add_delegate(parity_set_client(&client, &miner, &network).to_delegate()); io.add_delegate(parity_set_client(&client, &miner, &updater, &network).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "parity_setAuthor", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#; let request = r#"{"jsonrpc": "2.0", "method": "parity_setAuthor", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
@ -111,8 +157,9 @@ fn rpc_parity_set_engine_signer() {
let miner = miner_service(); let miner = miner_service();
let client = client_service(); let client = client_service();
let network = network_service(); let network = network_service();
let updater = updater_service();
let io = IoHandler::new(); let io = IoHandler::new();
io.add_delegate(parity_set_client(&client, &miner, &network).to_delegate()); io.add_delegate(parity_set_client(&client, &miner, &updater, &network).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "parity_setEngineSigner", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681", "password"], "id": 1}"#; let request = r#"{"jsonrpc": "2.0", "method": "parity_setEngineSigner", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681", "password"], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
@ -128,8 +175,9 @@ fn rpc_parity_set_transactions_limit() {
let miner = miner_service(); let miner = miner_service();
let client = client_service(); let client = client_service();
let network = network_service(); let network = network_service();
let updater = updater_service();
let io = IoHandler::new(); let io = IoHandler::new();
io.add_delegate(parity_set_client(&client, &miner, &network).to_delegate()); io.add_delegate(parity_set_client(&client, &miner, &updater, &network).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "parity_setTransactionsLimit", "params":[10240240], "id": 1}"#; let request = r#"{"jsonrpc": "2.0", "method": "parity_setTransactionsLimit", "params":[10240240], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
@ -143,8 +191,9 @@ fn rpc_parity_set_hash_content() {
let miner = miner_service(); let miner = miner_service();
let client = client_service(); let client = client_service();
let network = network_service(); let network = network_service();
let updater = updater_service();
let io = IoHandler::new(); let io = IoHandler::new();
io.add_delegate(parity_set_client(&client, &miner, &network).to_delegate()); io.add_delegate(parity_set_client(&client, &miner, &updater, &network).to_delegate());
let request = r#"{"jsonrpc": "2.0", "method": "parity_hashContent", "params":["https://ethcore.io/assets/images/ethcore-black-horizontal.png"], "id": 1}"#; let request = r#"{"jsonrpc": "2.0", "method": "parity_hashContent", "params":["https://ethcore.io/assets/images/ethcore-black-horizontal.png"], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e","id":1}"#; let response = r#"{"jsonrpc":"2.0","result":"0x2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e","id":1}"#;

View File

@ -25,7 +25,8 @@ use v1::types::{
H160, H256, H512, U256, Bytes, H160, H256, H512, U256, Bytes,
Peers, Transaction, RpcSettings, Histogram, Peers, Transaction, RpcSettings, Histogram,
TransactionStats, LocalTransactionStatus, TransactionStats, LocalTransactionStatus,
BlockNumber BlockNumber, ConsensusCapability, VersionInfo,
OperationsInfo
}; };
build_rpc_trait! { build_rpc_trait! {
@ -157,5 +158,17 @@ build_rpc_trait! {
/// Returns accounts information. /// Returns accounts information.
#[rpc(name = "parity_accounts")] #[rpc(name = "parity_accounts")]
fn accounts(&self) -> Result<BTreeMap<String, BTreeMap<String, String>>, Error>; fn accounts(&self) -> Result<BTreeMap<String, BTreeMap<String, String>>, Error>;
/// Returns information on current consensus capability.
#[rpc(name = "parity_consensusCapability")]
fn consensus_capability(&self) -> Result<ConsensusCapability, Error>;
/// Get our version information in a nice object.
#[rpc(name = "parity_versionInfo")]
fn version_info(&self) -> Result<VersionInfo, Error>;
/// Get information concerning the latest releases if available.
#[rpc(name = "parity_releasesInfo")]
fn releases_info(&self) -> Result<Option<OperationsInfo>, Error>;
} }
} }

View File

@ -19,7 +19,7 @@
use jsonrpc_core::Error; use jsonrpc_core::Error;
use jsonrpc_macros::Ready; use jsonrpc_macros::Ready;
use v1::types::{Bytes, H160, H256, U256}; use v1::types::{Bytes, H160, H256, U256, ReleaseInfo};
build_rpc_trait! { build_rpc_trait! {
/// Parity-specific rpc interface for operations altering the settings. /// Parity-specific rpc interface for operations altering the settings.
@ -91,5 +91,13 @@ build_rpc_trait! {
/// Hash a file content under given URL. /// Hash a file content under given URL.
#[rpc(async, name = "parity_hashContent")] #[rpc(async, name = "parity_hashContent")]
fn hash_content(&self, Ready<H256>, String); fn hash_content(&self, Ready<H256>, String);
/// Is there a release ready for install?
#[rpc(name = "parity_upgradeReady")]
fn upgrade_ready(&self) -> Result<Option<ReleaseInfo>, Error>;
/// Execute a release which is ready according to upgrade_ready().
#[rpc(name = "parity_executeUpgrade")]
fn execute_upgrade(&self) -> Result<bool, Error>;
} }
} }

View File

@ -0,0 +1,169 @@
// 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 semver;
use v1::types::{H160, H256};
use updater::{self, CapState};
/// Capability info
#[derive(Debug, PartialEq, Serialize)]
pub enum ConsensusCapability {
/// Unknown.
#[serde(rename="unknown")]
Unknown,
/// Capable of consensus indefinitely.
#[serde(rename="capable")]
Capable,
/// Capable of consensus up until a definite block.
#[serde(rename="capableUntil")]
CapableUntil(u64),
/// Incapable of consensus since a particular block.
#[serde(rename="incapableSince")]
IncapableSince(u64),
}
impl Into<ConsensusCapability> for CapState {
fn into(self) -> ConsensusCapability {
match self {
CapState::Unknown => ConsensusCapability::Unknown,
CapState::Capable => ConsensusCapability::Capable,
CapState::CapableUntil(n) => ConsensusCapability::CapableUntil(n),
CapState::IncapableSince(n) => ConsensusCapability::IncapableSince(n),
}
}
}
/// A release's track.
#[derive(Debug, PartialEq, Serialize)]
pub enum ReleaseTrack {
/// Stable track.
#[serde(rename="stable")]
Stable,
/// Beta track.
#[serde(rename="beta")]
Beta,
/// Nightly track.
#[serde(rename="nightly")]
Nightly,
/// Testing track.
#[serde(rename="testing")]
Testing,
/// No known track.
#[serde(rename="null")]
Unknown,
}
impl Into<ReleaseTrack> for updater::ReleaseTrack {
fn into(self) -> ReleaseTrack {
match self {
updater::ReleaseTrack::Stable => ReleaseTrack::Stable,
updater::ReleaseTrack::Beta => ReleaseTrack::Beta,
updater::ReleaseTrack::Nightly => ReleaseTrack::Nightly,
updater::ReleaseTrack::Testing => ReleaseTrack::Testing,
updater::ReleaseTrack::Unknown => ReleaseTrack::Unknown,
}
}
}
/// Semantic version.
#[derive(Debug, PartialEq, Serialize)]
pub struct Version {
/// Major part.
major: u64,
/// Minor part.
minor: u64,
/// Patch part.
patch: u64,
}
impl Into<Version> for semver::Version {
fn into(self) -> Version {
Version {
major: self.major,
minor: self.minor,
patch: self.patch,
}
}
}
/// Version information of a particular release.
#[derive(Debug, PartialEq, Serialize)]
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 Into<VersionInfo> for updater::VersionInfo {
fn into(self) -> VersionInfo {
VersionInfo {
track: self.track.into(),
version: self.version.into(),
hash: self.hash.into(),
}
}
}
/// Information regarding a particular release of Parity
#[derive(Debug, PartialEq, Serialize)]
pub struct ReleaseInfo {
/// Information on the version.
pub version: VersionInfo,
/// Does this release contain critical security updates?
pub is_critical: bool,
/// The latest fork that this release can handle.
pub fork: u64,
/// Our platform's binary, if known.
pub binary: Option<H256>,
}
impl Into<ReleaseInfo> for updater::ReleaseInfo {
fn into(self) -> ReleaseInfo {
ReleaseInfo {
version: self.version.into(),
is_critical: self.is_critical,
fork: self.fork,
binary: self.binary.map(Into::into),
}
}
}
/// Information on our operations environment.
#[derive(Debug, PartialEq, Serialize)]
pub struct OperationsInfo {
/// Our blockchain's latest fork.
pub fork: u64,
/// Last fork our client supports, if known.
pub this_fork: Option<u64>,
/// Information on our track's latest release.
pub track: ReleaseInfo,
/// Information on our minor version's latest release.
pub minor: Option<ReleaseInfo>,
}
impl Into<OperationsInfo> for updater::OperationsInfo {
fn into(self) -> OperationsInfo {
OperationsInfo {
fork: self.fork,
this_fork: self.this_fork,
track: self.track.into(),
minor: self.minor.map(Into::into),
}
}
}

View File

@ -34,6 +34,7 @@ mod trace_filter;
mod uint; mod uint;
mod work; mod work;
mod histogram; mod histogram;
mod consensus_status;
pub use self::bytes::Bytes; pub use self::bytes::Bytes;
pub use self::block::{RichBlock, Block, BlockTransactions}; pub use self::block::{RichBlock, Block, BlockTransactions};
@ -58,3 +59,4 @@ pub use self::trace_filter::TraceFilter;
pub use self::uint::{U128, U256}; pub use self::uint::{U128, U256};
pub use self::work::Work; pub use self::work::Work;
pub use self::histogram::Histogram; pub use self::histogram::Histogram;
pub use self::consensus_status::*;

View File

@ -117,7 +117,7 @@ fn reject_transaction(
// cmds // cmds
pub fn cmd_signer_list( pub fn signer_list(
signerport: u16, authfile: PathBuf signerport: u16, authfile: PathBuf
) -> Result<String, String> { ) -> Result<String, String> {
let addr = &format!("ws://127.0.0.1:{}", signerport); let addr = &format!("ws://127.0.0.1:{}", signerport);
@ -127,7 +127,7 @@ pub fn cmd_signer_list(
list_transactions(&mut signer) list_transactions(&mut signer)
} }
pub fn cmd_signer_reject( pub fn signer_reject(
id: Option<usize>, signerport: u16, authfile: PathBuf id: Option<usize>, signerport: u16, authfile: PathBuf
) -> Result<String, String> { ) -> Result<String, String> {
let id = try!(id.ok_or(format!("id required for signer reject"))); let id = try!(id.ok_or(format!("id required for signer reject")));
@ -138,7 +138,7 @@ pub fn cmd_signer_reject(
reject_transaction(&mut signer, U256::from(id)) reject_transaction(&mut signer, U256::from(id))
} }
pub fn cmd_signer_sign( pub fn signer_sign(
id: Option<usize>, id: Option<usize>,
pwfile: Option<PathBuf>, pwfile: Option<PathBuf>,
signerport: u16, signerport: u16,

222
scripts/contractABI.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -19,7 +19,7 @@ ethcore-devtools = { path = "../devtools" }
lazy_static = "0.2" lazy_static = "0.2"
env_logger = "0.3" env_logger = "0.3"
ethcore-ipc = { path = "../ipc/rpc" } ethcore-ipc = { path = "../ipc/rpc" }
semver = "0.2" semver = "0.5"
ethcore-ipc-nano = { path = "../ipc/nano" } ethcore-ipc-nano = { path = "../ipc/nano" }
[profile.release] [profile.release]

View File

@ -25,7 +25,7 @@ time = "0.1.34"
rand = "0.3.13" rand = "0.3.13"
heapsize = "0.3" heapsize = "0.3"
ethcore-ipc = { path = "../ipc/rpc" } ethcore-ipc = { path = "../ipc/rpc" }
semver = "0.2" semver = "0.5"
ethcore-ipc-nano = { path = "../ipc/nano" } ethcore-ipc-nano = { path = "../ipc/nano" }
ethcore-devtools = { path = "../devtools" } ethcore-devtools = { path = "../devtools" }
ethkey = { path = "../ethkey" } ethkey = { path = "../ethkey" }

View File

@ -94,7 +94,7 @@ use rlp::*;
use network::*; use network::*;
use ethcore::views::{HeaderView}; use ethcore::views::{HeaderView};
use ethcore::header::{BlockNumber, Header as BlockHeader}; use ethcore::header::{BlockNumber, Header as BlockHeader};
use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo, BlockImportError}; use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo, BlockImportError, BlockQueueInfo};
use ethcore::error::*; use ethcore::error::*;
use ethcore::snapshot::{ManifestData, RestorationStatus}; use ethcore::snapshot::{ManifestData, RestorationStatus};
use sync_io::SyncIo; use sync_io::SyncIo;
@ -235,6 +235,13 @@ impl SyncStatus {
min_peers min_peers
} }
} }
/// Is it doing a major sync?
pub fn is_syncing(&self, queue_info: BlockQueueInfo) -> bool {
let is_syncing_state = match self.state { SyncState::Idle | SyncState::NewBlocks => false, _ => true };
let is_verifying = queue_info.unverified_queue_size + queue_info.verified_queue_size > 3;
is_verifying || is_syncing_state
}
} }
#[derive(PartialEq, Eq, Debug, Clone)] #[derive(PartialEq, Eq, Debug, Clone)]
@ -2112,6 +2119,48 @@ mod tests {
rlp.out() rlp.out()
} }
fn queue_info(unverified: usize, verified: usize) -> BlockQueueInfo {
BlockQueueInfo {
unverified_queue_size: unverified,
verified_queue_size: verified,
verifying_queue_size: 0,
max_queue_size: 1000,
max_mem_use: 1000,
mem_used: 500
}
}
fn sync_status(state: SyncState) -> SyncStatus {
SyncStatus {
state: state,
protocol_version: 0,
network_id: 0,
start_block_number: 0,
last_imported_block_number: None,
highest_block_number: None,
blocks_total: 0,
blocks_received: 0,
num_peers: 0,
num_active_peers: 0,
mem_used: 0,
num_snapshot_chunks: 0,
snapshot_chunks_done: 0,
last_imported_old_block_number: None,
}
}
#[test]
fn is_still_verifying() {
assert!(!sync_status(SyncState::Idle).is_syncing(queue_info(2, 1)));
assert!(sync_status(SyncState::Idle).is_syncing(queue_info(2, 2)));
}
#[test]
fn is_synced_state() {
assert!(sync_status(SyncState::Blocks).is_syncing(queue_info(0, 0)));
assert!(!sync_status(SyncState::Idle).is_syncing(queue_info(0, 0)));
}
#[test] #[test]
fn return_receipts_empty() { fn return_receipts_empty() {
let mut client = TestBlockChainClient::new(); let mut client = TestBlockChainClient::new();

24
updater/Cargo.toml Normal file
View File

@ -0,0 +1,24 @@
[package]
description = "Parity Updater Service."
name = "parity-updater"
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"
ethabi = "0.2.2"
ethcore = { path = "../ethcore" }
ethsync = { path = "../sync" }
ethcore-util = { path = "../util" }
parity-hash-fetch = { path = "../hash-fetch" }
ipc-common-types = { path = "../ipc-common-types" }
ethcore-ipc = { path = "../ipc/rpc" }
[profile.release]
debug = true
lto = false

22
updater/build.rs Normal file
View File

@ -0,0 +1,22 @@
// 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();
ethcore_ipc_codegen::derive_ipc_cond("src/service.rs", cfg!(feature="ipc")).unwrap();
}

39
updater/src/lib.rs Normal file
View File

@ -0,0 +1,39 @@
// 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 ethcore_util as util;
extern crate ipc_common_types;
extern crate parity_hash_fetch as hash_fetch;
extern crate ethcore;
extern crate ethabi;
extern crate ethsync;
extern crate ethcore_ipc as ipc;
mod updater;
mod operations;
mod types;
mod service {
#![allow(dead_code, unused_assignments, unused_variables, missing_docs)] // codegen issues
include!(concat!(env!("OUT_DIR"), "/service.rs"));
}
pub use service::{Service};
pub use types::all::{ReleaseInfo, OperationsInfo, CapState, VersionInfo, ReleaseTrack};
pub use updater::{Updater, UpdateFilter, UpdatePolicy};

359
updater/src/operations.rs Normal file

File diff suppressed because one or more lines are too long

40
updater/src/service.rs Normal file
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/>.
use types::all::{CapState, ReleaseInfo, OperationsInfo};
use ipc_common_types::VersionInfo;
#[ipc(client_ident="RemoteUpdater")]
pub trait Service: Send + Sync {
/// Is the currently running client capable of supporting the current chain?
/// We default to true if there's no clear information.
fn capability(&self) -> CapState;
/// The release which is ready to be upgraded to, if any. If this returns `Some`, then
/// `execute_upgrade` may be called.
fn upgrade_ready(&self) -> Option<ReleaseInfo>;
/// Actually upgrades the client. Assumes that the binary has been downloaded.
/// @returns `true` on success.
fn execute_upgrade(&self) -> bool;
/// Our version info.
fn version_info(&self) -> VersionInfo;
/// Information gathered concerning the release.
fn info(&self) -> Option<OperationsInfo>;
}

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