Merge branch 'master' of github.com:ethcore/parity into tx-block
This commit is contained in:
		
						commit
						6c9de9e6f8
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -32,3 +32,5 @@ | |||||||
| out/ | out/ | ||||||
| 
 | 
 | ||||||
| .vscode | .vscode | ||||||
|  | 
 | ||||||
|  | /parity.* | ||||||
|  | |||||||
| @ -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 | ||||||
|  | |||||||
							
								
								
									
										94
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										94
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -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" | ||||||
| @ -1312,6 +1316,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" | ||||||
| @ -1351,11 +1367,26 @@ dependencies = [ | |||||||
| [[package]] | [[package]] | ||||||
| name = "parity-ui-precompiled" | name = "parity-ui-precompiled" | ||||||
| version = "1.4.0" | version = "1.4.0" | ||||||
| source = "git+https://github.com/ethcore/js-precompiled.git#2d07c405453bcf1e603c3965387b7f920565b6d8" | source = "git+https://github.com/ethcore/js-precompiled.git#3d390b35737ce212d358f26b5ec8d9644b252a88" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", |  "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "parity-updater" | ||||||
|  | version = "1.5.0" | ||||||
|  | dependencies = [ | ||||||
|  |  "ethabi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
|  |  "ethcore 1.5.0", | ||||||
|  |  "ethcore-ipc 1.5.0", | ||||||
|  |  "ethcore-ipc-codegen 1.5.0", | ||||||
|  |  "ethcore-util 1.5.0", | ||||||
|  |  "ethsync 1.5.0", | ||||||
|  |  "ipc-common-types 1.5.0", | ||||||
|  |  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
|  |  "parity-hash-fetch 1.5.0", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "parking_lot" | name = "parking_lot" | ||||||
| version = "0.3.6" | version = "0.3.6" | ||||||
| @ -1674,6 +1705,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" | ||||||
| @ -2240,6 +2288,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" | ||||||
|  | |||||||
							
								
								
									
										15
									
								
								Cargo.toml
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								Cargo.toml
									
									
									
									
									
								
							| @ -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" | ||||||
|  | |||||||
| @ -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} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -120,7 +120,7 @@ impl<R: URLHint> ContentFetcher<R> { | |||||||
| 				// Content is already being fetched
 | 				// Content is already being fetched
 | ||||||
| 				Some(&mut ContentStatus::Fetching(ref fetch_control)) => { | 				Some(&mut ContentStatus::Fetching(ref fetch_control)) => { | ||||||
| 					trace!(target: "dapps", "Content fetching in progress. Waiting..."); | 					trace!(target: "dapps", "Content fetching in progress. Waiting..."); | ||||||
| 					(None, fetch_control.to_handler(control)) | 					(None, fetch_control.to_async_handler(path, control)) | ||||||
| 				}, | 				}, | ||||||
| 				// We need to start fetching the content
 | 				// We need to start fetching the content
 | ||||||
| 				None => { | 				None => { | ||||||
| @ -129,11 +129,12 @@ impl<R: URLHint> ContentFetcher<R> { | |||||||
| 					let content = self.resolver.resolve(content_hex); | 					let content = self.resolver.resolve(content_hex); | ||||||
| 
 | 
 | ||||||
| 					let cache = self.cache.clone(); | 					let cache = self.cache.clone(); | ||||||
| 					let on_done = move |id: String, result: Option<LocalPageEndpoint>| { | 					let id = content_id.clone(); | ||||||
|  | 					let on_done = move |result: Option<LocalPageEndpoint>| { | ||||||
| 						let mut cache = cache.lock(); | 						let mut cache = cache.lock(); | ||||||
| 						match result { | 						match result { | ||||||
| 							Some(endpoint) => { | 							Some(endpoint) => { | ||||||
| 								cache.insert(id, ContentStatus::Ready(endpoint)); | 								cache.insert(id.clone(), ContentStatus::Ready(endpoint)); | ||||||
| 							}, | 							}, | ||||||
| 							// In case of error
 | 							// In case of error
 | ||||||
| 							None => { | 							None => { | ||||||
| @ -150,6 +151,7 @@ impl<R: URLHint> ContentFetcher<R> { | |||||||
| 						Some(URLHintResult::Dapp(dapp)) => { | 						Some(URLHintResult::Dapp(dapp)) => { | ||||||
| 							let (handler, fetch_control) = ContentFetcherHandler::new( | 							let (handler, fetch_control) = ContentFetcherHandler::new( | ||||||
| 								dapp.url(), | 								dapp.url(), | ||||||
|  | 								path, | ||||||
| 								control, | 								control, | ||||||
| 								DappInstaller { | 								DappInstaller { | ||||||
| 									id: content_id.clone(), | 									id: content_id.clone(), | ||||||
| @ -165,6 +167,7 @@ impl<R: URLHint> ContentFetcher<R> { | |||||||
| 						Some(URLHintResult::Content(content)) => { | 						Some(URLHintResult::Content(content)) => { | ||||||
| 							let (handler, fetch_control) = ContentFetcherHandler::new( | 							let (handler, fetch_control) = ContentFetcherHandler::new( | ||||||
| 								content.url, | 								content.url, | ||||||
|  | 								path, | ||||||
| 								control, | 								control, | ||||||
| 								ContentInstaller { | 								ContentInstaller { | ||||||
| 									id: content_id.clone(), | 									id: content_id.clone(), | ||||||
| @ -248,43 +251,45 @@ struct ContentInstaller { | |||||||
| 	id: String, | 	id: String, | ||||||
| 	mime: String, | 	mime: String, | ||||||
| 	content_path: PathBuf, | 	content_path: PathBuf, | ||||||
| 	on_done: Box<Fn(String, Option<LocalPageEndpoint>) + Send>, | 	on_done: Box<Fn(Option<LocalPageEndpoint>) + Send>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl ContentValidator for ContentInstaller { | impl ContentValidator for ContentInstaller { | ||||||
| 	type Error = ValidationError; | 	type Error = ValidationError; | ||||||
| 
 | 
 | ||||||
| 	fn validate_and_install(&self, path: PathBuf) -> Result<(String, LocalPageEndpoint), ValidationError> { | 	fn validate_and_install(&self, path: PathBuf) -> Result<LocalPageEndpoint, ValidationError> { | ||||||
| 		// Create dir
 | 		let validate = || { | ||||||
| 		try!(fs::create_dir_all(&self.content_path)); | 			// Create dir
 | ||||||
|  | 			try!(fs::create_dir_all(&self.content_path)); | ||||||
| 
 | 
 | ||||||
| 		// Validate hash
 | 			// Validate hash
 | ||||||
| 		let mut file_reader = io::BufReader::new(try!(fs::File::open(&path))); | 			let mut file_reader = io::BufReader::new(try!(fs::File::open(&path))); | ||||||
| 		let hash = try!(sha3(&mut file_reader)); | 			let hash = try!(sha3(&mut file_reader)); | ||||||
| 		let id = try!(self.id.as_str().parse().map_err(|_| ValidationError::InvalidContentId)); | 			let id = try!(self.id.as_str().parse().map_err(|_| ValidationError::InvalidContentId)); | ||||||
| 		if id != hash { | 			if id != hash { | ||||||
| 			return Err(ValidationError::HashMismatch { | 				return Err(ValidationError::HashMismatch { | ||||||
| 				expected: id, | 					expected: id, | ||||||
| 				got: hash, | 					got: hash, | ||||||
| 			}); | 				}); | ||||||
| 		} | 			} | ||||||
| 
 | 
 | ||||||
| 		// And prepare path for a file
 | 			// And prepare path for a file
 | ||||||
| 		let filename = path.file_name().expect("We always fetch a file."); | 			let filename = path.file_name().expect("We always fetch a file."); | ||||||
| 		let mut content_path = self.content_path.clone(); | 			let mut content_path = self.content_path.clone(); | ||||||
| 		content_path.push(&filename); | 			content_path.push(&filename); | ||||||
| 
 | 
 | ||||||
| 		if content_path.exists() { | 			if content_path.exists() { | ||||||
| 			try!(fs::remove_dir_all(&content_path)) | 				try!(fs::remove_dir_all(&content_path)) | ||||||
| 		} | 			} | ||||||
| 
 | 
 | ||||||
| 		try!(fs::copy(&path, &content_path)); | 			try!(fs::copy(&path, &content_path)); | ||||||
|  | 			Ok(LocalPageEndpoint::single_file(content_path, self.mime.clone(), PageCache::Enabled)) | ||||||
|  | 		}; | ||||||
| 
 | 
 | ||||||
| 		Ok((self.id.clone(), LocalPageEndpoint::single_file(content_path, self.mime.clone(), PageCache::Enabled))) | 		// Make sure to always call on_done (even in case of errors)!
 | ||||||
| 	} | 		let result = validate(); | ||||||
| 
 | 		(self.on_done)(result.as_ref().ok().cloned()); | ||||||
| 	fn done(&self, endpoint: Option<LocalPageEndpoint>) { | 		result | ||||||
| 		(self.on_done)(self.id.clone(), endpoint) |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -292,7 +297,7 @@ impl ContentValidator for ContentInstaller { | |||||||
| struct DappInstaller { | struct DappInstaller { | ||||||
| 	id: String, | 	id: String, | ||||||
| 	dapps_path: PathBuf, | 	dapps_path: PathBuf, | ||||||
| 	on_done: Box<Fn(String, Option<LocalPageEndpoint>) + Send>, | 	on_done: Box<Fn(Option<LocalPageEndpoint>) + Send>, | ||||||
| 	embeddable_on: Option<(String, u16)>, | 	embeddable_on: Option<(String, u16)>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -331,69 +336,68 @@ impl DappInstaller { | |||||||
| impl ContentValidator for DappInstaller { | impl ContentValidator for DappInstaller { | ||||||
| 	type Error = ValidationError; | 	type Error = ValidationError; | ||||||
| 
 | 
 | ||||||
| 	fn validate_and_install(&self, app_path: PathBuf) -> Result<(String, LocalPageEndpoint), ValidationError> { | 	fn validate_and_install(&self, path: PathBuf) -> Result<LocalPageEndpoint, ValidationError> { | ||||||
| 		trace!(target: "dapps", "Opening dapp bundle at {:?}", app_path); | 		trace!(target: "dapps", "Opening dapp bundle at {:?}", path); | ||||||
| 		let mut file_reader = io::BufReader::new(try!(fs::File::open(app_path))); | 		let validate = || { | ||||||
| 		let hash = try!(sha3(&mut file_reader)); | 			let mut file_reader = io::BufReader::new(try!(fs::File::open(path))); | ||||||
| 		let id = try!(self.id.as_str().parse().map_err(|_| ValidationError::InvalidContentId)); | 			let hash = try!(sha3(&mut file_reader)); | ||||||
| 		if id != hash { | 			let id = try!(self.id.as_str().parse().map_err(|_| ValidationError::InvalidContentId)); | ||||||
| 			return Err(ValidationError::HashMismatch { | 			if id != hash { | ||||||
| 				expected: id, | 				return Err(ValidationError::HashMismatch { | ||||||
| 				got: hash, | 					expected: id, | ||||||
| 			}); | 					got: hash, | ||||||
| 		} | 				}); | ||||||
| 		let file = file_reader.into_inner(); | 			} | ||||||
| 		// Unpack archive
 | 			let file = file_reader.into_inner(); | ||||||
| 		let mut zip = try!(zip::ZipArchive::new(file)); | 			// Unpack archive
 | ||||||
| 		// First find manifest file
 | 			let mut zip = try!(zip::ZipArchive::new(file)); | ||||||
| 		let (mut manifest, manifest_dir) = try!(Self::find_manifest(&mut zip)); | 			// First find manifest file
 | ||||||
| 		// Overwrite id to match hash
 | 			let (mut manifest, manifest_dir) = try!(Self::find_manifest(&mut zip)); | ||||||
| 		manifest.id = self.id.clone(); | 			// Overwrite id to match hash
 | ||||||
|  | 			manifest.id = self.id.clone(); | ||||||
| 
 | 
 | ||||||
| 		let target = self.dapp_target_path(&manifest); | 			let target = self.dapp_target_path(&manifest); | ||||||
| 
 | 
 | ||||||
| 		// Remove old directory
 | 			// Remove old directory
 | ||||||
| 		if target.exists() { | 			if target.exists() { | ||||||
| 			warn!(target: "dapps", "Overwriting existing dapp: {}", manifest.id); | 				warn!(target: "dapps", "Overwriting existing dapp: {}", manifest.id); | ||||||
| 			try!(fs::remove_dir_all(target.clone())); | 				try!(fs::remove_dir_all(target.clone())); | ||||||
| 		} | 			} | ||||||
| 
 | 
 | ||||||
| 		// Unpack zip
 | 			// Unpack zip
 | ||||||
| 		for i in 0..zip.len() { | 			for i in 0..zip.len() { | ||||||
| 			let mut file = try!(zip.by_index(i)); | 				let mut file = try!(zip.by_index(i)); | ||||||
| 			// TODO [todr] Check if it's consistent on windows.
 | 				// TODO [todr] Check if it's consistent on windows.
 | ||||||
| 			let is_dir = file.name().chars().rev().next() == Some('/'); | 				let is_dir = file.name().chars().rev().next() == Some('/'); | ||||||
| 
 | 
 | ||||||
| 			let file_path = PathBuf::from(file.name()); | 				let file_path = PathBuf::from(file.name()); | ||||||
| 			let location_in_manifest_base = file_path.strip_prefix(&manifest_dir); | 				let location_in_manifest_base = file_path.strip_prefix(&manifest_dir); | ||||||
| 			// Create files that are inside manifest directory
 | 				// Create files that are inside manifest directory
 | ||||||
| 			if let Ok(location_in_manifest_base) = location_in_manifest_base { | 				if let Ok(location_in_manifest_base) = location_in_manifest_base { | ||||||
| 				let p = target.join(location_in_manifest_base); | 					let p = target.join(location_in_manifest_base); | ||||||
| 				// Check if it's a directory
 | 					// Check if it's a directory
 | ||||||
| 				if is_dir { | 					if is_dir { | ||||||
| 					try!(fs::create_dir_all(p)); | 						try!(fs::create_dir_all(p)); | ||||||
| 				} else { | 					} else { | ||||||
| 					let mut target = try!(fs::File::create(p)); | 						let mut target = try!(fs::File::create(p)); | ||||||
| 					try!(io::copy(&mut file, &mut target)); | 						try!(io::copy(&mut file, &mut target)); | ||||||
|  | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		// Write manifest
 | 			// Write manifest
 | ||||||
| 		let manifest_str = try!(serialize_manifest(&manifest).map_err(ValidationError::ManifestSerialization)); | 			let manifest_str = try!(serialize_manifest(&manifest).map_err(ValidationError::ManifestSerialization)); | ||||||
| 		let manifest_path = target.join(MANIFEST_FILENAME); | 			let manifest_path = target.join(MANIFEST_FILENAME); | ||||||
| 		let mut manifest_file = try!(fs::File::create(manifest_path)); | 			let mut manifest_file = try!(fs::File::create(manifest_path)); | ||||||
| 		try!(manifest_file.write_all(manifest_str.as_bytes())); | 			try!(manifest_file.write_all(manifest_str.as_bytes())); | ||||||
|  | 			// Create endpoint
 | ||||||
|  | 			let endpoint = LocalPageEndpoint::new(target, manifest.clone().into(), PageCache::Enabled, self.embeddable_on.clone()); | ||||||
|  | 			Ok(endpoint) | ||||||
|  | 		}; | ||||||
| 
 | 
 | ||||||
| 		// Create endpoint
 | 		let result = validate(); | ||||||
| 		let app = LocalPageEndpoint::new(target, manifest.clone().into(), PageCache::Enabled, self.embeddable_on.clone()); | 		(self.on_done)(result.as_ref().ok().cloned()); | ||||||
| 
 | 		result | ||||||
| 		// Return modified app manifest
 |  | ||||||
| 		Ok((manifest.id.clone(), app)) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	fn done(&self, endpoint: Option<LocalPageEndpoint>) { |  | ||||||
| 		(self.on_done)(self.id.clone(), endpoint) |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -22,35 +22,41 @@ use std::sync::{mpsc, Arc}; | |||||||
| use std::sync::atomic::{AtomicBool, Ordering}; | use std::sync::atomic::{AtomicBool, Ordering}; | ||||||
| use std::time::{Instant, Duration}; | use std::time::{Instant, Duration}; | ||||||
| use util::Mutex; | use util::Mutex; | ||||||
| use url::Url; |  | ||||||
| use fetch::{Client, Fetch, FetchResult}; | use fetch::{Client, Fetch, FetchResult}; | ||||||
| 
 | 
 | ||||||
| use hyper::{server, Decoder, Encoder, Next, Method, Control}; | use hyper::{server, Decoder, Encoder, Next, Method, Control}; | ||||||
| use hyper::net::HttpStream; | use hyper::net::HttpStream; | ||||||
|  | use hyper::uri::RequestUri; | ||||||
| use hyper::status::StatusCode; | use hyper::status::StatusCode; | ||||||
| 
 | 
 | ||||||
| use handlers::{ContentHandler, Redirection, extract_url}; | use endpoint::EndpointPath; | ||||||
| use page::LocalPageEndpoint; | use handlers::ContentHandler; | ||||||
|  | use page::{LocalPageEndpoint, PageHandlerWaiting}; | ||||||
| 
 | 
 | ||||||
| const FETCH_TIMEOUT: u64 = 30; | const FETCH_TIMEOUT: u64 = 30; | ||||||
| 
 | 
 | ||||||
| enum FetchState { | enum FetchState { | ||||||
|  | 	Waiting, | ||||||
| 	NotStarted(String), | 	NotStarted(String), | ||||||
| 	Error(ContentHandler), | 	Error(ContentHandler), | ||||||
| 	InProgress(mpsc::Receiver<FetchResult>), | 	InProgress(mpsc::Receiver<FetchResult>), | ||||||
| 	Done(String, LocalPageEndpoint, Redirection), | 	Done(LocalPageEndpoint, Box<PageHandlerWaiting>), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | enum WaitResult { | ||||||
|  | 	Error(ContentHandler), | ||||||
|  | 	Done(LocalPageEndpoint), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub trait ContentValidator { | pub trait ContentValidator { | ||||||
| 	type Error: fmt::Debug + fmt::Display; | 	type Error: fmt::Debug + fmt::Display; | ||||||
| 
 | 
 | ||||||
| 	fn validate_and_install(&self, app: PathBuf) -> Result<(String, LocalPageEndpoint), Self::Error>; | 	fn validate_and_install(&self, path: PathBuf) -> Result<LocalPageEndpoint, Self::Error>; | ||||||
| 	fn done(&self, Option<LocalPageEndpoint>); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub struct FetchControl { | pub struct FetchControl { | ||||||
| 	abort: Arc<AtomicBool>, | 	abort: Arc<AtomicBool>, | ||||||
| 	listeners: Mutex<Vec<(Control, mpsc::Sender<FetchState>)>>, | 	listeners: Mutex<Vec<(Control, mpsc::Sender<WaitResult>)>>, | ||||||
| 	deadline: Instant, | 	deadline: Instant, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -65,9 +71,10 @@ impl Default for FetchControl { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl FetchControl { | impl FetchControl { | ||||||
| 	fn notify<F: Fn() -> FetchState>(&self, status: F) { | 	fn notify<F: Fn() -> WaitResult>(&self, status: F) { | ||||||
| 		let mut listeners = self.listeners.lock(); | 		let mut listeners = self.listeners.lock(); | ||||||
| 		for (control, sender) in listeners.drain(..) { | 		for (control, sender) in listeners.drain(..) { | ||||||
|  | 			trace!(target: "dapps", "Resuming request waiting for content..."); | ||||||
| 			if let Err(e) = sender.send(status()) { | 			if let Err(e) = sender.send(status()) { | ||||||
| 				trace!(target: "dapps", "Waiting listener notification failed: {:?}", e); | 				trace!(target: "dapps", "Waiting listener notification failed: {:?}", e); | ||||||
| 			} else { | 			} else { | ||||||
| @ -78,9 +85,9 @@ impl FetchControl { | |||||||
| 
 | 
 | ||||||
| 	fn set_status(&self, status: &FetchState) { | 	fn set_status(&self, status: &FetchState) { | ||||||
| 		match *status { | 		match *status { | ||||||
| 			FetchState::Error(ref handler) => self.notify(|| FetchState::Error(handler.clone())), | 			FetchState::Error(ref handler) => self.notify(|| WaitResult::Error(handler.clone())), | ||||||
| 			FetchState::Done(ref id, ref endpoint, ref handler) => self.notify(|| FetchState::Done(id.clone(), endpoint.clone(), handler.clone())), | 			FetchState::Done(ref endpoint, _) => self.notify(|| WaitResult::Done(endpoint.clone())), | ||||||
| 			FetchState::NotStarted(_) | FetchState::InProgress(_) => {}, | 			FetchState::NotStarted(_) | FetchState::InProgress(_) | FetchState::Waiting => {}, | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -88,44 +95,66 @@ impl FetchControl { | |||||||
| 		self.abort.store(true, Ordering::SeqCst); | 		self.abort.store(true, Ordering::SeqCst); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	pub fn to_handler(&self, control: Control) -> Box<server::Handler<HttpStream> + Send> { | 	pub fn to_async_handler(&self, path: EndpointPath, control: Control) -> Box<server::Handler<HttpStream> + Send> { | ||||||
| 		let (tx, rx) = mpsc::channel(); | 		let (tx, rx) = mpsc::channel(); | ||||||
| 		self.listeners.lock().push((control, tx)); | 		self.listeners.lock().push((control, tx)); | ||||||
| 
 | 
 | ||||||
| 		Box::new(WaitingHandler { | 		Box::new(WaitingHandler { | ||||||
| 			receiver: rx, | 			receiver: rx, | ||||||
| 			state: None, | 			state: FetchState::Waiting, | ||||||
|  | 			uri: RequestUri::default(), | ||||||
|  | 			path: path, | ||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub struct WaitingHandler { | pub struct WaitingHandler { | ||||||
| 	receiver: mpsc::Receiver<FetchState>, | 	receiver: mpsc::Receiver<WaitResult>, | ||||||
| 	state: Option<FetchState>, | 	state: FetchState, | ||||||
|  | 	uri: RequestUri, | ||||||
|  | 	path: EndpointPath, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl server::Handler<HttpStream> for WaitingHandler { | impl server::Handler<HttpStream> for WaitingHandler { | ||||||
| 	fn on_request(&mut self, _request: server::Request<HttpStream>) -> Next { | 	fn on_request(&mut self, request: server::Request<HttpStream>) -> Next { | ||||||
|  | 		self.uri = request.uri().clone(); | ||||||
| 		Next::wait() | 		Next::wait() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn on_request_readable(&mut self, _decoder: &mut Decoder<HttpStream>) -> Next { | 	fn on_request_readable(&mut self, decoder: &mut Decoder<HttpStream>) -> Next { | ||||||
| 		self.state = self.receiver.try_recv().ok(); | 		let result = self.receiver.try_recv().ok(); | ||||||
| 		Next::write() | 		self.state = match result { | ||||||
|  | 			Some(WaitResult::Error(handler)) => FetchState::Error(handler), | ||||||
|  | 			Some(WaitResult::Done(endpoint)) => { | ||||||
|  | 				let mut page_handler = endpoint.to_page_handler(self.path.clone()); | ||||||
|  | 				page_handler.set_uri(&self.uri); | ||||||
|  | 				FetchState::Done(endpoint, page_handler) | ||||||
|  | 			}, | ||||||
|  | 			None => { | ||||||
|  | 				warn!("A result for waiting request was not received."); | ||||||
|  | 				FetchState::Waiting | ||||||
|  | 			}, | ||||||
|  | 		}; | ||||||
|  | 
 | ||||||
|  | 		match self.state { | ||||||
|  | 			FetchState::Done(_, ref mut handler) => handler.on_request_readable(decoder), | ||||||
|  | 			FetchState::Error(ref mut handler) => handler.on_request_readable(decoder), | ||||||
|  | 			_ => Next::write(), | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn on_response(&mut self, res: &mut server::Response) -> Next { | 	fn on_response(&mut self, res: &mut server::Response) -> Next { | ||||||
| 		match self.state { | 		match self.state { | ||||||
| 			Some(FetchState::Done(_, _, ref mut handler)) => handler.on_response(res), | 			FetchState::Done(_, ref mut handler) => handler.on_response(res), | ||||||
| 			Some(FetchState::Error(ref mut handler)) => handler.on_response(res), | 			FetchState::Error(ref mut handler) => handler.on_response(res), | ||||||
| 			_ => Next::end(), | 			_ => Next::end(), | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next { | 	fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next { | ||||||
| 		match self.state { | 		match self.state { | ||||||
| 			Some(FetchState::Done(_, _, ref mut handler)) => handler.on_response_writable(encoder), | 			FetchState::Done(_, ref mut handler) => handler.on_response_writable(encoder), | ||||||
| 			Some(FetchState::Error(ref mut handler)) => handler.on_response_writable(encoder), | 			FetchState::Error(ref mut handler) => handler.on_response_writable(encoder), | ||||||
| 			_ => Next::end(), | 			_ => Next::end(), | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @ -137,29 +166,19 @@ pub struct ContentFetcherHandler<H: ContentValidator> { | |||||||
| 	status: FetchState, | 	status: FetchState, | ||||||
| 	client: Option<Client>, | 	client: Option<Client>, | ||||||
| 	installer: H, | 	installer: H, | ||||||
| 	request_url: Option<Url>, | 	path: EndpointPath, | ||||||
|  | 	uri: RequestUri, | ||||||
| 	embeddable_on: Option<(String, u16)>, | 	embeddable_on: Option<(String, u16)>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<H: ContentValidator> Drop for ContentFetcherHandler<H> { |  | ||||||
| 	fn drop(&mut self) { |  | ||||||
| 		let result = match self.status { |  | ||||||
| 			FetchState::Done(_, ref result, _) => Some(result.clone()), |  | ||||||
| 			_ => None, |  | ||||||
| 		}; |  | ||||||
| 		self.installer.done(result); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<H: ContentValidator> ContentFetcherHandler<H> { | impl<H: ContentValidator> ContentFetcherHandler<H> { | ||||||
| 
 |  | ||||||
| 	pub fn new( | 	pub fn new( | ||||||
| 		url: String, | 		url: String, | ||||||
|  | 		path: EndpointPath, | ||||||
| 		control: Control, | 		control: Control, | ||||||
| 		handler: H, | 		handler: H, | ||||||
| 		embeddable_on: Option<(String, u16)>, | 		embeddable_on: Option<(String, u16)>, | ||||||
| 	) -> (Self, Arc<FetchControl>) { | 	) -> (Self, Arc<FetchControl>) { | ||||||
| 
 |  | ||||||
| 		let fetch_control = Arc::new(FetchControl::default()); | 		let fetch_control = Arc::new(FetchControl::default()); | ||||||
| 		let client = Client::default(); | 		let client = Client::default(); | ||||||
| 		let handler = ContentFetcherHandler { | 		let handler = ContentFetcherHandler { | ||||||
| @ -168,7 +187,8 @@ impl<H: ContentValidator> ContentFetcherHandler<H> { | |||||||
| 			client: Some(client), | 			client: Some(client), | ||||||
| 			status: FetchState::NotStarted(url), | 			status: FetchState::NotStarted(url), | ||||||
| 			installer: handler, | 			installer: handler, | ||||||
| 			request_url: None, | 			path: path, | ||||||
|  | 			uri: RequestUri::default(), | ||||||
| 			embeddable_on: embeddable_on, | 			embeddable_on: embeddable_on, | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| @ -192,7 +212,6 @@ impl<H: ContentValidator> ContentFetcherHandler<H> { | |||||||
| 
 | 
 | ||||||
| impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<H> { | impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<H> { | ||||||
| 	fn on_request(&mut self, request: server::Request<HttpStream>) -> Next { | 	fn on_request(&mut self, request: server::Request<HttpStream>) -> Next { | ||||||
| 		self.request_url = extract_url(&request); |  | ||||||
| 		let status = if let FetchState::NotStarted(ref url) = self.status { | 		let status = if let FetchState::NotStarted(ref url) = self.status { | ||||||
| 			Some(match *request.method() { | 			Some(match *request.method() { | ||||||
| 				// Start fetching content
 | 				// Start fetching content
 | ||||||
| @ -205,8 +224,8 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler< | |||||||
| 						Ok(receiver) => FetchState::InProgress(receiver), | 						Ok(receiver) => FetchState::InProgress(receiver), | ||||||
| 						Err(e) => FetchState::Error(ContentHandler::error( | 						Err(e) => FetchState::Error(ContentHandler::error( | ||||||
| 							StatusCode::BadGateway, | 							StatusCode::BadGateway, | ||||||
| 							"Unable To Start Dapp Download", | 							"Unable To Start Content Download", | ||||||
| 							"Could not initialize download of the dapp. It might be a problem with the remote server.", | 							"Could not initialize download of the content. It might be a problem with the remote server.", | ||||||
| 							Some(&format!("{}", e)), | 							Some(&format!("{}", e)), | ||||||
| 							self.embeddable_on.clone(), | 							self.embeddable_on.clone(), | ||||||
| 						)), | 						)), | ||||||
| @ -227,6 +246,7 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler< | |||||||
| 			self.fetch_control.set_status(&status); | 			self.fetch_control.set_status(&status); | ||||||
| 			self.status = status; | 			self.status = status; | ||||||
| 		} | 		} | ||||||
|  | 		self.uri = request.uri().clone(); | ||||||
| 
 | 
 | ||||||
| 		Next::read() | 		Next::read() | ||||||
| 	} | 	} | ||||||
| @ -266,11 +286,10 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler< | |||||||
| 									self.embeddable_on.clone(), | 									self.embeddable_on.clone(), | ||||||
| 								)) | 								)) | ||||||
| 							}, | 							}, | ||||||
| 							Ok((id, result)) => { | 							Ok(endpoint) => { | ||||||
| 								let url: String = self.request_url.take() | 								let mut handler = endpoint.to_page_handler(self.path.clone()); | ||||||
| 									.map(|url| url.raw.into_string()) | 								handler.set_uri(&self.uri); | ||||||
| 									.expect("Request URL always read in on_request; qed"); | 								FetchState::Done(endpoint, handler) | ||||||
| 								FetchState::Done(id, result, Redirection::new(&url)) |  | ||||||
| 							}, | 							}, | ||||||
| 						}; | 						}; | ||||||
| 						// Remove temporary zip file
 | 						// Remove temporary zip file
 | ||||||
| @ -306,7 +325,7 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler< | |||||||
| 
 | 
 | ||||||
| 	fn on_response(&mut self, res: &mut server::Response) -> Next { | 	fn on_response(&mut self, res: &mut server::Response) -> Next { | ||||||
| 		match self.status { | 		match self.status { | ||||||
| 			FetchState::Done(_, _, ref mut handler) => handler.on_response(res), | 			FetchState::Done(_, ref mut handler) => handler.on_response(res), | ||||||
| 			FetchState::Error(ref mut handler) => handler.on_response(res), | 			FetchState::Error(ref mut handler) => handler.on_response(res), | ||||||
| 			_ => Next::end(), | 			_ => Next::end(), | ||||||
| 		} | 		} | ||||||
| @ -314,7 +333,7 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler< | |||||||
| 
 | 
 | ||||||
| 	fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next { | 	fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next { | ||||||
| 		match self.status { | 		match self.status { | ||||||
| 			FetchState::Done(_, _, ref mut handler) => handler.on_response_writable(encoder), | 			FetchState::Done(_, ref mut handler) => handler.on_response_writable(encoder), | ||||||
| 			FetchState::Error(ref mut handler) => handler.on_response_writable(encoder), | 			FetchState::Error(ref mut handler) => handler.on_response_writable(encoder), | ||||||
| 			_ => Next::end(), | 			_ => Next::end(), | ||||||
| 		} | 		} | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
| @ -83,13 +83,19 @@ impl Default for PageCache { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// A generic type for `PageHandler` allowing to set the URL.
 | ||||||
|  | /// Used by dapps fetching to set the URL after the content was downloaded.
 | ||||||
|  | pub trait PageHandlerWaiting: server::Handler<HttpStream> + Send { | ||||||
|  | 	fn set_uri(&mut self, uri: &RequestUri); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /// A handler for a single webapp.
 | /// A handler for a single webapp.
 | ||||||
| /// Resolves correct paths and serves as a plumbing code between
 | /// Resolves correct paths and serves as a plumbing code between
 | ||||||
| /// hyper server and dapp.
 | /// hyper server and dapp.
 | ||||||
| pub struct PageHandler<T: Dapp> { | pub struct PageHandler<T: Dapp> { | ||||||
| 	/// A Dapp.
 | 	/// A Dapp.
 | ||||||
| 	pub app: T, | 	pub app: T, | ||||||
| 	/// File currently being served (or `None` if file does not exist).
 | 	/// File currently being served
 | ||||||
| 	pub file: ServedFile<T>, | 	pub file: ServedFile<T>, | ||||||
| 	/// Optional prefix to strip from path.
 | 	/// Optional prefix to strip from path.
 | ||||||
| 	pub prefix: Option<String>, | 	pub prefix: Option<String>, | ||||||
| @ -101,6 +107,21 @@ pub struct PageHandler<T: Dapp> { | |||||||
| 	pub cache: PageCache, | 	pub cache: PageCache, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl<T: Dapp> PageHandlerWaiting for PageHandler<T> { | ||||||
|  | 	fn set_uri(&mut self, uri: &RequestUri) { | ||||||
|  | 		trace!(target: "dapps", "Setting URI: {:?}", uri); | ||||||
|  | 		self.file = match *uri { | ||||||
|  | 			RequestUri::AbsolutePath { ref path, .. } => { | ||||||
|  | 				self.app.file(&self.extract_path(path)) | ||||||
|  | 			}, | ||||||
|  | 			RequestUri::AbsoluteUri(ref url) => { | ||||||
|  | 				self.app.file(&self.extract_path(url.path())) | ||||||
|  | 			}, | ||||||
|  | 			_ => None, | ||||||
|  | 		}.map_or_else(|| ServedFile::new(self.safe_to_embed_on.clone()), |f| ServedFile::File(f)); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| impl<T: Dapp> PageHandler<T> { | impl<T: Dapp> PageHandler<T> { | ||||||
| 	fn extract_path(&self, path: &str) -> String { | 	fn extract_path(&self, path: &str) -> String { | ||||||
| 		let app_id = &self.path.app_id; | 		let app_id = &self.path.app_id; | ||||||
| @ -124,15 +145,7 @@ impl<T: Dapp> PageHandler<T> { | |||||||
| 
 | 
 | ||||||
| impl<T: Dapp> server::Handler<HttpStream> for PageHandler<T> { | impl<T: Dapp> server::Handler<HttpStream> for PageHandler<T> { | ||||||
| 	fn on_request(&mut self, req: server::Request<HttpStream>) -> Next { | 	fn on_request(&mut self, req: server::Request<HttpStream>) -> Next { | ||||||
| 		self.file = match *req.uri() { | 		self.set_uri(req.uri()); | ||||||
| 			RequestUri::AbsolutePath { ref path, .. } => { |  | ||||||
| 				self.app.file(&self.extract_path(path)) |  | ||||||
| 			}, |  | ||||||
| 			RequestUri::AbsoluteUri(ref url) => { |  | ||||||
| 				self.app.file(&self.extract_path(url.path())) |  | ||||||
| 			}, |  | ||||||
| 			_ => None, |  | ||||||
| 		}.map_or_else(|| ServedFile::new(self.safe_to_embed_on.clone()), |f| ServedFile::File(f)); |  | ||||||
| 		Next::write() | 		Next::write() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ use mime_guess; | |||||||
| use std::io::{Seek, Read, SeekFrom}; | use std::io::{Seek, Read, SeekFrom}; | ||||||
| use std::fs; | use std::fs; | ||||||
| use std::path::{Path, PathBuf}; | use std::path::{Path, PathBuf}; | ||||||
| use page::handler::{self, PageCache}; | use page::handler::{self, PageCache, PageHandlerWaiting}; | ||||||
| use endpoint::{Endpoint, EndpointInfo, EndpointPath, Handler}; | use endpoint::{Endpoint, EndpointInfo, EndpointPath, Handler}; | ||||||
| 
 | 
 | ||||||
| #[derive(Debug, Clone)] | #[derive(Debug, Clone)] | ||||||
| @ -54,6 +54,36 @@ impl LocalPageEndpoint { | |||||||
| 	pub fn path(&self) -> PathBuf { | 	pub fn path(&self) -> PathBuf { | ||||||
| 		self.path.clone() | 		self.path.clone() | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	fn page_handler_with_mime(&self, path: EndpointPath, mime: &str) -> handler::PageHandler<LocalSingleFile> { | ||||||
|  | 		handler::PageHandler { | ||||||
|  | 			app: LocalSingleFile { path: self.path.clone(), mime: mime.into() }, | ||||||
|  | 			prefix: None, | ||||||
|  | 			path: path, | ||||||
|  | 			file: handler::ServedFile::new(None), | ||||||
|  | 			safe_to_embed_on: self.embeddable_on.clone(), | ||||||
|  | 			cache: self.cache, | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	fn page_handler(&self, path: EndpointPath) -> handler::PageHandler<LocalDapp> { | ||||||
|  | 		handler::PageHandler { | ||||||
|  | 			app: LocalDapp { path: self.path.clone() }, | ||||||
|  | 			prefix: None, | ||||||
|  | 			path: path, | ||||||
|  | 			file: handler::ServedFile::new(None), | ||||||
|  | 			safe_to_embed_on: self.embeddable_on.clone(), | ||||||
|  | 			cache: self.cache, | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	pub fn to_page_handler(&self, path: EndpointPath) -> Box<PageHandlerWaiting> { | ||||||
|  | 		if let Some(ref mime) = self.mime { | ||||||
|  | 			Box::new(self.page_handler_with_mime(path, mime)) | ||||||
|  | 		} else { | ||||||
|  | 			Box::new(self.page_handler(path)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Endpoint for LocalPageEndpoint { | impl Endpoint for LocalPageEndpoint { | ||||||
| @ -63,23 +93,9 @@ impl Endpoint for LocalPageEndpoint { | |||||||
| 
 | 
 | ||||||
| 	fn to_handler(&self, path: EndpointPath) -> Box<Handler> { | 	fn to_handler(&self, path: EndpointPath) -> Box<Handler> { | ||||||
| 		if let Some(ref mime) = self.mime { | 		if let Some(ref mime) = self.mime { | ||||||
| 			Box::new(handler::PageHandler { | 			Box::new(self.page_handler_with_mime(path, mime)) | ||||||
| 				app: LocalSingleFile { path: self.path.clone(), mime: mime.clone() }, |  | ||||||
| 				prefix: None, |  | ||||||
| 				path: path, |  | ||||||
| 				file: handler::ServedFile::new(None), |  | ||||||
| 				safe_to_embed_on: self.embeddable_on.clone(), |  | ||||||
| 				cache: self.cache, |  | ||||||
| 			}) |  | ||||||
| 		} else { | 		} else { | ||||||
| 			Box::new(handler::PageHandler { | 			Box::new(self.page_handler(path)) | ||||||
| 				app: LocalDapp { path: self.path.clone() }, |  | ||||||
| 				prefix: None, |  | ||||||
| 				path: path, |  | ||||||
| 				file: handler::ServedFile::new(None), |  | ||||||
| 				safe_to_embed_on: self.embeddable_on.clone(), |  | ||||||
| 				cache: self.cache, |  | ||||||
| 			}) |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -21,5 +21,5 @@ mod handler; | |||||||
| 
 | 
 | ||||||
| pub use self::local::LocalPageEndpoint; | pub use self::local::LocalPageEndpoint; | ||||||
| pub use self::builtin::PageEndpoint; | pub use self::builtin::PageEndpoint; | ||||||
| pub use self::handler::PageCache; | pub use self::handler::{PageCache, PageHandlerWaiting}; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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.
 | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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" | ||||||
|  | |||||||
| @ -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, | ||||||
|  | |||||||
| @ -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" | ||||||
|  | |||||||
| @ -15,7 +15,8 @@ | |||||||
| 				"eip155Transition": 10, | 				"eip155Transition": 10, | ||||||
| 				"eip160Transition": 10, | 				"eip160Transition": 10, | ||||||
| 				"eip161abcTransition": 10, | 				"eip161abcTransition": 10, | ||||||
| 				"eip161dTransition": 10 | 				"eip161dTransition": 10, | ||||||
|  | 				"maxCodeSize": 24576 | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	}, | 	}, | ||||||
|  | |||||||
| @ -1 +1 @@ | |||||||
| Subproject commit e8f4624b7f1a15c63674eecf577c7ab76c3b16be | Subproject commit 9028c4801fd39fbb71a9796979182549a24e81c8 | ||||||
| @ -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, PendingTransaction, Action}; | use transaction::{LocalizedTransaction, SignedTransaction, Transaction, PendingTransaction, Action}; | ||||||
| use blockchain::extras::TransactionAddress; | use blockchain::extras::TransactionAddress; | ||||||
| use types::filter::Filter; | use types::filter::Filter; | ||||||
| use types::mode::Mode as IpcMode; | use types::mode::Mode as IpcMode; | ||||||
| @ -68,6 +70,7 @@ use factory::Factories; | |||||||
| use rlp::{decode, View, UntrustedRlp}; | use rlp::{decode, View, UntrustedRlp}; | ||||||
| use state_db::StateDB; | use state_db::StateDB; | ||||||
| use rand::OsRng; | use rand::OsRng; | ||||||
|  | use client::registry::Registry; | ||||||
| 
 | 
 | ||||||
| // re-export
 | // re-export
 | ||||||
| pub use types::blockchain_info::BlockChainInfo; | pub use types::blockchain_info::BlockChainInfo; | ||||||
| @ -124,6 +127,7 @@ impl SleepState { | |||||||
| /// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue.
 | /// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue.
 | ||||||
| /// Call `import_block()` to import a block asynchronously; `flush_queue()` flushes the queue.
 | /// Call `import_block()` to import a block asynchronously; `flush_queue()` flushes the queue.
 | ||||||
| pub struct Client { | pub struct Client { | ||||||
|  | 	enabled: AtomicBool, | ||||||
| 	mode: Mutex<Mode>, | 	mode: Mutex<Mode>, | ||||||
| 	chain: RwLock<Arc<BlockChain>>, | 	chain: RwLock<Arc<BlockChain>>, | ||||||
| 	tracedb: RwLock<TraceDB<BlockChain>>, | 	tracedb: RwLock<TraceDB<BlockChain>>, | ||||||
| @ -148,6 +152,7 @@ pub struct Client { | |||||||
| 	history: u64, | 	history: u64, | ||||||
| 	rng: Mutex<OsRng>, | 	rng: Mutex<OsRng>, | ||||||
| 	on_mode_change: Mutex<Option<Box<FnMut(&Mode) + 'static + Send>>>, | 	on_mode_change: Mutex<Option<Box<FnMut(&Mode) + 'static + Send>>>, | ||||||
|  | 	registrar: Mutex<Option<Registry>>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Client { | impl Client { | ||||||
| @ -160,6 +165,7 @@ impl Client { | |||||||
| 		message_channel: IoChannel<ClientIoMessage>, | 		message_channel: IoChannel<ClientIoMessage>, | ||||||
| 		db_config: &DatabaseConfig, | 		db_config: &DatabaseConfig, | ||||||
| 	) -> Result<Arc<Client>, ClientError> { | 	) -> Result<Arc<Client>, ClientError> { | ||||||
|  | 
 | ||||||
| 		let path = path.to_path_buf(); | 		let path = path.to_path_buf(); | ||||||
| 		let gb = spec.genesis_block(); | 		let gb = spec.genesis_block(); | ||||||
| 
 | 
 | ||||||
| @ -221,7 +227,8 @@ impl Client { | |||||||
| 			accountdb: Default::default(), | 			accountdb: Default::default(), | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 		let client = Client { | 		let client = Arc::new(Client { | ||||||
|  | 			enabled: AtomicBool::new(true), | ||||||
| 			sleep_state: Mutex::new(SleepState::new(awake)), | 			sleep_state: Mutex::new(SleepState::new(awake)), | ||||||
| 			liveness: AtomicBool::new(awake), | 			liveness: AtomicBool::new(awake), | ||||||
| 			mode: Mutex::new(config.mode.clone()), | 			mode: Mutex::new(config.mode.clone()), | ||||||
| @ -246,8 +253,15 @@ impl Client { | |||||||
| 			history: history, | 			history: history, | ||||||
| 			rng: Mutex::new(try!(OsRng::new().map_err(::util::UtilError::StdIo))), | 			rng: Mutex::new(try!(OsRng::new().map_err(::util::UtilError::StdIo))), | ||||||
| 			on_mode_change: Mutex::new(None), | 			on_mode_change: Mutex::new(None), | ||||||
| 		}; | 			registrar: Mutex::new(None), | ||||||
| 		Ok(Arc::new(client)) | 		}); | ||||||
|  | 		if let Some(reg_addr) = client.additional_params().get("registrar").and_then(|s| Address::from_str(s).ok()) { | ||||||
|  | 			trace!(target: "client", "Found registrar at {}", reg_addr); | ||||||
|  | 			let weak = Arc::downgrade(&client); | ||||||
|  | 			let registrar = Registry::new(reg_addr, move |a, d| weak.upgrade().ok_or("No client!".into()).and_then(|c| c.call_contract(a, d))); | ||||||
|  | 			*client.registrar.lock() = Some(registrar); | ||||||
|  | 		} | ||||||
|  | 		Ok(client) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/// Adds an actor to be notified on certain events
 | 	/// Adds an actor to be notified on certain events
 | ||||||
| @ -268,6 +282,11 @@ impl Client { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/// Get the Registry object - useful for looking up names.
 | ||||||
|  | 	pub fn registrar(&self) -> MutexGuard<Option<Registry>> { | ||||||
|  | 		self.registrar.lock() | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	/// Register an action to be done if a mode change happens.
 | 	/// Register an action to be done if a mode change happens.
 | ||||||
| 	pub fn on_mode_change<F>(&self, f: F) where F: 'static + FnMut(&Mode) + Send { | 	pub fn on_mode_change<F>(&self, f: F) where F: 'static + FnMut(&Mode) + Send { | ||||||
| 		*self.on_mode_change.lock() = Some(Box::new(f)); | 		*self.on_mode_change.lock() = Some(Box::new(f)); | ||||||
| @ -395,6 +414,12 @@ impl Client { | |||||||
| 
 | 
 | ||||||
| 	/// This is triggered by a message coming from a block queue when the block is ready for insertion
 | 	/// This is triggered by a message coming from a block queue when the block is ready for insertion
 | ||||||
| 	pub fn import_verified_blocks(&self) -> usize { | 	pub fn import_verified_blocks(&self) -> usize { | ||||||
|  | 
 | ||||||
|  | 		// Shortcut out if we know we're incapable of syncing the chain.
 | ||||||
|  | 		if !self.enabled.load(AtomicOrdering::Relaxed) { | ||||||
|  | 			return 0; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		let max_blocks_to_import = 4; | 		let max_blocks_to_import = 4; | ||||||
| 		let (imported_blocks, import_results, invalid_blocks, imported, proposed_blocks, duration, is_empty) = { | 		let (imported_blocks, import_results, invalid_blocks, imported, proposed_blocks, duration, is_empty) = { | ||||||
| 			let mut imported_blocks = Vec::with_capacity(max_blocks_to_import); | 			let mut imported_blocks = Vec::with_capacity(max_blocks_to_import); | ||||||
| @ -663,10 +688,17 @@ impl Client { | |||||||
| 	/// Tick the client.
 | 	/// Tick the client.
 | ||||||
| 	// TODO: manage by real events.
 | 	// TODO: manage by real events.
 | ||||||
| 	pub fn tick(&self) { | 	pub fn tick(&self) { | ||||||
|  | 		self.check_garbage(); | ||||||
|  | 		self.check_snooze(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	fn check_garbage(&self) { | ||||||
| 		self.chain.read().collect_garbage(); | 		self.chain.read().collect_garbage(); | ||||||
| 		self.block_queue.collect_garbage(); | 		self.block_queue.collect_garbage(); | ||||||
| 		self.tracedb.read().collect_garbage(); | 		self.tracedb.read().collect_garbage(); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
|  | 	fn check_snooze(&self) { | ||||||
| 		let mode = self.mode.lock().clone(); | 		let mode = self.mode.lock().clone(); | ||||||
| 		match mode { | 		match mode { | ||||||
| 			Mode::Dark(timeout) => { | 			Mode::Dark(timeout) => { | ||||||
| @ -700,16 +732,6 @@ impl Client { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/// Look up the block number for the given block ID.
 |  | ||||||
| 	pub fn block_number(&self, id: BlockId) -> Option<BlockNumber> { |  | ||||||
| 		match id { |  | ||||||
| 			BlockId::Number(number) => Some(number), |  | ||||||
| 			BlockId::Hash(ref hash) => self.chain.read().block_number(hash), |  | ||||||
| 			BlockId::Earliest => Some(0), |  | ||||||
| 			BlockId::Latest | BlockId::Pending => Some(self.chain.read().best_block_number()), |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/// Take a snapshot at the given block.
 | 	/// Take a snapshot at the given block.
 | ||||||
| 	/// If the ID given is "latest", this will default to 1000 blocks behind.
 | 	/// If the ID given is "latest", this will default to 1000 blocks behind.
 | ||||||
| 	pub fn take_snapshot<W: snapshot_io::SnapshotWriter + Send>(&self, writer: W, at: BlockId, p: &snapshot::Progress) -> Result<(), EthcoreError> { | 	pub fn take_snapshot<W: snapshot_io::SnapshotWriter + Send>(&self, writer: W, at: BlockId, p: &snapshot::Progress) -> Result<(), EthcoreError> { | ||||||
| @ -908,8 +930,17 @@ impl BlockChainClient for Client { | |||||||
| 		r | 		r | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	fn disable(&self) { | ||||||
|  | 		self.set_mode(IpcMode::Off); | ||||||
|  | 		self.enabled.store(false, AtomicOrdering::Relaxed); | ||||||
|  | 		self.clear_queue(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	fn set_mode(&self, new_mode: IpcMode) { | 	fn set_mode(&self, new_mode: IpcMode) { | ||||||
| 		trace!(target: "mode", "Client::set_mode({:?})", new_mode); | 		trace!(target: "mode", "Client::set_mode({:?})", new_mode); | ||||||
|  | 		if !self.enabled.load(AtomicOrdering::Relaxed) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
| 		{ | 		{ | ||||||
| 			let mut mode = self.mode.lock(); | 			let mut mode = self.mode.lock(); | ||||||
| 			*mode = new_mode.clone().into(); | 			*mode = new_mode.clone().into(); | ||||||
| @ -935,6 +966,15 @@ impl BlockChainClient for Client { | |||||||
| 		Self::block_hash(&chain, id).and_then(|hash| chain.block_header_data(&hash)) | 		Self::block_hash(&chain, id).and_then(|hash| chain.block_header_data(&hash)) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	fn block_number(&self, id: BlockId) -> Option<BlockNumber> { | ||||||
|  | 		match id { | ||||||
|  | 			BlockId::Number(number) => Some(number), | ||||||
|  | 			BlockId::Hash(ref hash) => self.chain.read().block_number(hash), | ||||||
|  | 			BlockId::Earliest => Some(0), | ||||||
|  | 			BlockId::Latest | BlockId::Pending => Some(self.chain.read().best_block_number()), | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	fn block_body(&self, id: BlockId) -> Option<Bytes> { | 	fn block_body(&self, id: BlockId) -> Option<Bytes> { | ||||||
| 		let chain = self.chain.read(); | 		let chain = self.chain.read(); | ||||||
| 		Self::block_hash(&chain, id).and_then(|hash| chain.block_body(&hash)) | 		Self::block_hash(&chain, id).and_then(|hash| chain.block_body(&hash)) | ||||||
| @ -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 { | ||||||
|  | |||||||
| @ -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}; | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
							
								
								
									
										264
									
								
								ethcore/src/client/registry.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								ethcore/src/client/registry.rs
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -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 } | ||||||
| } | } | ||||||
|  | |||||||
| @ -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 { } | ||||||
|  | |||||||
| @ -100,6 +100,7 @@ impl AsMillis for Duration { | |||||||
| impl AuthorityRound { | impl AuthorityRound { | ||||||
| 	/// Create a new instance of AuthorityRound engine.
 | 	/// Create a new instance of AuthorityRound engine.
 | ||||||
| 	pub fn new(params: CommonParams, our_params: AuthorityRoundParams, builtins: BTreeMap<Address, Builtin>) -> Result<Arc<Self>, Error> { | 	pub fn new(params: CommonParams, our_params: AuthorityRoundParams, builtins: BTreeMap<Address, Builtin>) -> Result<Arc<Self>, Error> { | ||||||
|  | 		let should_timeout = our_params.start_step.is_none(); | ||||||
| 		let initial_step = our_params.start_step.unwrap_or_else(|| (unix_now().as_secs() / our_params.step_duration.as_secs())) as usize; | 		let initial_step = our_params.start_step.unwrap_or_else(|| (unix_now().as_secs() / our_params.step_duration.as_secs())) as usize; | ||||||
| 		let engine = Arc::new( | 		let engine = Arc::new( | ||||||
| 			AuthorityRound { | 			AuthorityRound { | ||||||
| @ -113,18 +114,17 @@ impl AuthorityRound { | |||||||
| 				account_provider: Mutex::new(None), | 				account_provider: Mutex::new(None), | ||||||
| 				password: RwLock::new(None), | 				password: RwLock::new(None), | ||||||
| 			}); | 			}); | ||||||
| 		let handler = TransitionHandler { engine: Arc::downgrade(&engine) }; | 		// Do not initialize timeouts for tests.
 | ||||||
| 		try!(engine.transition_service.register_handler(Arc::new(handler))); | 		if should_timeout { | ||||||
|  | 			let handler = TransitionHandler { engine: Arc::downgrade(&engine) }; | ||||||
|  | 			try!(engine.transition_service.register_handler(Arc::new(handler))); | ||||||
|  | 		} | ||||||
| 		Ok(engine) | 		Ok(engine) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn step(&self) -> usize { |  | ||||||
| 		self.step.load(AtomicOrdering::SeqCst) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	fn remaining_step_duration(&self) -> Duration { | 	fn remaining_step_duration(&self) -> Duration { | ||||||
| 		let now = unix_now(); | 		let now = unix_now(); | ||||||
| 		let step_end = self.our_params.step_duration * (self.step() as u32 + 1); | 		let step_end = self.our_params.step_duration * (self.step.load(AtomicOrdering::SeqCst) as u32 + 1); | ||||||
| 		if step_end > now { | 		if step_end > now { | ||||||
| 			step_end - now | 			step_end - now | ||||||
| 		} else { | 		} else { | ||||||
| @ -228,7 +228,7 @@ impl Engine for AuthorityRound { | |||||||
| 	fn generate_seal(&self, block: &ExecutedBlock) -> Seal { | 	fn generate_seal(&self, block: &ExecutedBlock) -> Seal { | ||||||
| 		if self.proposed.load(AtomicOrdering::SeqCst) { return Seal::None; } | 		if self.proposed.load(AtomicOrdering::SeqCst) { return Seal::None; } | ||||||
| 		let header = block.header(); | 		let header = block.header(); | ||||||
| 		let step = self.step(); | 		let step = self.step.load(AtomicOrdering::SeqCst); | ||||||
| 		if self.is_step_proposer(step, header.author()) { | 		if self.is_step_proposer(step, header.author()) { | ||||||
| 			if let Some(ref ap) = *self.account_provider.lock() { | 			if let Some(ref ap) = *self.account_provider.lock() { | ||||||
| 				// Account should be permanently unlocked, otherwise sealing will fail.
 | 				// Account should be permanently unlocked, otherwise sealing will fail.
 | ||||||
| @ -265,7 +265,7 @@ impl Engine for AuthorityRound { | |||||||
| 	fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> { | 	fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> { | ||||||
| 		let header_step = try!(header_step(header)); | 		let header_step = try!(header_step(header)); | ||||||
| 		// Give one step slack if step is lagging, double vote is still not possible.
 | 		// Give one step slack if step is lagging, double vote is still not possible.
 | ||||||
| 		if header_step <= self.step() + 1 { | 		if header_step <= self.step.load(AtomicOrdering::SeqCst) + 1 { | ||||||
| 			let proposer_signature = try!(header_signature(header)); | 			let proposer_signature = try!(header_signature(header)); | ||||||
| 			let ok_sig = try!(verify_address(self.step_proposer(header_step), &proposer_signature, &header.bare_hash())); | 			let ok_sig = try!(verify_address(self.step_proposer(header_step), &proposer_signature, &header.bare_hash())); | ||||||
| 			if ok_sig { | 			if ok_sig { | ||||||
|  | |||||||
| @ -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") | ||||||
| } | } | ||||||
|  | |||||||
| @ -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; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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")) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -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; | ||||||
							
								
								
									
										40
									
								
								ethcore/src/types/security_level.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								ethcore/src/types/security_level.rs
									
									
									
									
									
										Normal 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, | ||||||
|  | 		} 
 | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -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" } | ||||||
| @ -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) | ||||||
| 	} | 	} | ||||||
| @ -30,4 +30,4 @@ mod client; | |||||||
| 
 | 
 | ||||||
| pub mod urlhint; | pub mod urlhint; | ||||||
| 
 | 
 | ||||||
| pub use client::{HashFetch, Client}; | pub use client::{HashFetch, Client, Error}; | ||||||
							
								
								
									
										20
									
								
								ipc-common-types/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								ipc-common-types/Cargo.toml
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										21
									
								
								ipc-common-types/build.rs
									
									
									
									
									
										Normal 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(); | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								ipc-common-types/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								ipc-common-types/src/lib.rs
									
									
									
									
									
										Normal 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::*; | ||||||
							
								
								
									
										21
									
								
								ipc-common-types/src/types/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								ipc-common-types/src/types/mod.rs
									
									
									
									
									
										Normal 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")); | ||||||
|  | 
 | ||||||
							
								
								
									
										21
									
								
								ipc-common-types/src/types/mod.rs.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								ipc-common-types/src/types/mod.rs.in
									
									
									
									
									
										Normal 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}; | ||||||
							
								
								
									
										82
									
								
								ipc-common-types/src/types/release_track.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								ipc-common-types/src/types/release_track.rs
									
									
									
									
									
										Normal 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, 
 | ||||||
|  | 		}		
 | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										68
									
								
								ipc-common-types/src/types/version_info.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								ipc-common-types/src/types/version_info.rs
									
									
									
									
									
										Normal 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, | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -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) | ||||||
| 							}; | 							}; | ||||||
| 						} | 						} | ||||||
|  | |||||||
| @ -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" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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" | ||||||
|  | |||||||
| @ -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() { | ||||||
|  | |||||||
| @ -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}; | ||||||
|  | |||||||
| @ -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" } | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "parity.js", |   "name": "parity.js", | ||||||
|   "version": "0.2.126", |   "version": "0.2.128", | ||||||
|   "main": "release/index.js", |   "main": "release/index.js", | ||||||
|   "jsnext:main": "src/index.js", |   "jsnext:main": "src/index.js", | ||||||
|   "author": "Parity Team <admin@parity.io>", |   "author": "Parity Team <admin@parity.io>", | ||||||
| @ -36,7 +36,7 @@ | |||||||
|     "ci:build:npm": "NODE_ENV=production webpack --config webpack/npm", |     "ci:build:npm": "NODE_ENV=production webpack --config webpack/npm", | ||||||
|     "start": "npm install && npm run build:lib && npm run build:dll && npm run start:app", |     "start": "npm install && npm run build:lib && npm run build:dll && npm run start:app", | ||||||
|     "start:app": "node webpack/dev.server", |     "start:app": "node webpack/dev.server", | ||||||
|     "clean": "rm -rf ./build ./coverage", |     "clean": "rm -rf ./.build ./.coverage ./.happypack ./.npmjs ./build", | ||||||
|     "coveralls": "npm run testCoverage && coveralls < coverage/lcov.info", |     "coveralls": "npm run testCoverage && coveralls < coverage/lcov.info", | ||||||
|     "lint": "npm run lint:css && npm run lint:js", |     "lint": "npm run lint:css && npm run lint:js", | ||||||
|     "lint:cached": "npm run lint:css && npm run lint:js:cached", |     "lint:cached": "npm run lint:css && npm run lint:js:cached", | ||||||
|  | |||||||
| @ -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; }) | ||||||
|   }; |   }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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 | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|       }); |       }); | ||||||
|     }); |     }); | ||||||
|   }); |   }); | ||||||
|  | |||||||
| @ -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'); | ||||||
|  |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
| @ -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)' | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  | |||||||
							
								
								
									
										17
									
								
								js/src/modals/UpgradeParity/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								js/src/modals/UpgradeParity/index.js
									
									
									
									
									
										Normal 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'; | ||||||
							
								
								
									
										146
									
								
								js/src/modals/UpgradeParity/store.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								js/src/modals/UpgradeParity/store.js
									
									
									
									
									
										Normal 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 | ||||||
|  | }; | ||||||
							
								
								
									
										58
									
								
								js/src/modals/UpgradeParity/store.spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								js/src/modals/UpgradeParity/store.spec.js
									
									
									
									
									
										Normal 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/); | ||||||
|  |       }); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
							
								
								
									
										32
									
								
								js/src/modals/UpgradeParity/upgradeParity.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								js/src/modals/UpgradeParity/upgradeParity.css
									
									
									
									
									
										Normal 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; | ||||||
|  | } | ||||||
							
								
								
									
										257
									
								
								js/src/modals/UpgradeParity/upgradeParity.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								js/src/modals/UpgradeParity/upgradeParity.js
									
									
									
									
									
										Normal 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}`; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -23,6 +23,8 @@ import VerificationStore, { | |||||||
| } from './store'; | } from './store'; | ||||||
| import { postToServer } from '../../3rdparty/email-verification'; | import { postToServer } from '../../3rdparty/email-verification'; | ||||||
| 
 | 
 | ||||||
|  | const EMAIL_VERIFICATION = 4; // id in the `BadgeReg.sol` contract
 | ||||||
|  | 
 | ||||||
| export default class EmailVerificationStore extends VerificationStore { | export default class EmailVerificationStore extends VerificationStore { | ||||||
|   @observable email = ''; |   @observable email = ''; | ||||||
| 
 | 
 | ||||||
| @ -54,7 +56,7 @@ export default class EmailVerificationStore extends VerificationStore { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   constructor (api, account, isTestnet) { |   constructor (api, account, isTestnet) { | ||||||
|     super(api, EmailVerificationABI, 'emailverification3', account, isTestnet); |     super(api, EmailVerificationABI, EMAIL_VERIFICATION, account, isTestnet); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   requestValues = () => [ sha3(this.email) ] |   requestValues = () => [ sha3(this.email) ] | ||||||
|  | |||||||
| @ -23,6 +23,8 @@ import VerificationStore, { | |||||||
| } from './store'; | } from './store'; | ||||||
| import { postToServer } from '../../3rdparty/sms-verification'; | import { postToServer } from '../../3rdparty/sms-verification'; | ||||||
| 
 | 
 | ||||||
|  | const SMS_VERIFICATION = 0; // id in the `BadgeReg.sol` contract
 | ||||||
|  | 
 | ||||||
| export default class SMSVerificationStore extends VerificationStore { | export default class SMSVerificationStore extends VerificationStore { | ||||||
|   @observable number = ''; |   @observable number = ''; | ||||||
| 
 | 
 | ||||||
| @ -53,7 +55,7 @@ export default class SMSVerificationStore extends VerificationStore { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   constructor (api, account, isTestnet) { |   constructor (api, account, isTestnet) { | ||||||
|     super(api, SMSVerificationABI, 'smsverification', account, isTestnet); |     super(api, SMSVerificationABI, SMS_VERIFICATION, account, isTestnet); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @action setNumber = (number) => { |   @action setNumber = (number) => { | ||||||
|  | |||||||
| @ -46,13 +46,13 @@ export default class VerificationStore { | |||||||
|   @observable isCodeValid = null; |   @observable isCodeValid = null; | ||||||
|   @observable confirmationTx = null; |   @observable confirmationTx = null; | ||||||
| 
 | 
 | ||||||
|   constructor (api, abi, name, account, isTestnet) { |   constructor (api, abi, certifierId, account, isTestnet) { | ||||||
|     this.api = api; |     this.api = api; | ||||||
|     this.account = account; |     this.account = account; | ||||||
|     this.isTestnet = isTestnet; |     this.isTestnet = isTestnet; | ||||||
| 
 | 
 | ||||||
|     this.step = LOADING; |     this.step = LOADING; | ||||||
|     Contracts.get().badgeReg.fetchCertifier(name) |     Contracts.get().badgeReg.fetchCertifier(certifierId) | ||||||
|       .then(({ address }) => { |       .then(({ address }) => { | ||||||
|         this.contract = new Contract(api, abi).at(address); |         this.contract = new Contract(api, abi).at(address); | ||||||
|         this.load(); |         this.load(); | ||||||
|  | |||||||
| @ -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
									
								
							
							
						
						
									
										31
									
								
								js/src/ui/Icons/index.js
									
									
									
									
									
										Normal 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 | ||||||
|  | }; | ||||||
| @ -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 }> | ||||||
|  | |||||||
| @ -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> | ||||||
|  | |||||||
| @ -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 { | ||||||
|  | |||||||
| @ -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 | ||||||
|  | |||||||
| @ -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, | ||||||
|  | |||||||
| @ -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> | ||||||
|  | |||||||
| @ -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); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -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 | ||||||
|  | |||||||
| @ -22,5 +22,5 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .content { | .content { | ||||||
|   padding-bottom: 1em; |   padding-bottom: 1.25em; | ||||||
| } | } | ||||||
|  | |||||||
| @ -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 | ||||||
|   }; |   }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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 { | ||||||
|  | |||||||
| @ -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> | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -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 { | ||||||
|  | |||||||
| @ -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
 | ||||||
| @ -180,7 +179,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result<String, String> { | |||||||
| 	let snapshot_path = db_dirs.snapshot_path(); | 	let snapshot_path = db_dirs.snapshot_path(); | ||||||
| 
 | 
 | ||||||
| 	// execute upgrades
 | 	// execute upgrades
 | ||||||
| 	try!(execute_upgrades(&db_dirs, algorithm, cmd.compaction.compaction_profile(db_dirs.db_root_path().as_path()))); | 	try!(execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, cmd.compaction.compaction_profile(db_dirs.db_root_path().as_path()))); | ||||||
| 
 | 
 | ||||||
| 	// create dirs used by parity
 | 	// create dirs used by parity
 | ||||||
| 	try!(cmd.dirs.create_dirs(false, false)); | 	try!(cmd.dirs.create_dirs(false, false)); | ||||||
| @ -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()); | ||||||
| @ -351,7 +348,7 @@ fn start_client( | |||||||
| 	let snapshot_path = db_dirs.snapshot_path(); | 	let snapshot_path = db_dirs.snapshot_path(); | ||||||
| 
 | 
 | ||||||
| 	// execute upgrades
 | 	// execute upgrades
 | ||||||
| 	try!(execute_upgrades(&db_dirs, algorithm, compaction.compaction_profile(db_dirs.db_root_path().as_path()))); | 	try!(execute_upgrades(&dirs.base, &db_dirs, algorithm, compaction.compaction_profile(db_dirs.db_root_path().as_path()))); | ||||||
| 
 | 
 | ||||||
| 	// create dirs used by parity
 | 	// create dirs used by parity
 | ||||||
| 	try!(dirs.create_dirs(false, false)); | 	try!(dirs.create_dirs(false, false)); | ||||||
| @ -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)] | ||||||
|  | |||||||
| @ -2,8 +2,14 @@ | |||||||
| 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" | base_path = "$HOME/.parity" | ||||||
|  | db_path = "$HOME/.parity/chains" | ||||||
| keys_path = "$HOME/.parity/keys" | keys_path = "$HOME/.parity/keys" | ||||||
| identity = "" | identity = "" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -85,9 +85,14 @@ 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_base_path: String = default_data_path(), or |c: &Config| otry!(c.parity).base_path.clone(), | ||||||
| 		flag_keys_path: String = "$DATA/keys", or |c: &Config| otry!(c.parity).keys_path.clone(), | 		flag_db_path: String = "$BASE/chains", or |c: &Config| otry!(c.parity).db_path.clone(), | ||||||
|  | 		flag_keys_path: String = "$BASE/keys", or |c: &Config| otry!(c.parity).keys_path.clone(), | ||||||
| 		flag_identity: String = "", or |c: &Config| otry!(c.parity).identity.clone(), | 		flag_identity: String = "", or |c: &Config| otry!(c.parity).identity.clone(), | ||||||
| 
 | 
 | ||||||
| 		// -- Account Options
 | 		// -- Account Options
 | ||||||
| @ -106,7 +111,7 @@ usage! { | |||||||
| 			or |c: &Config| otry!(c.ui).port.clone(), | 			or |c: &Config| otry!(c.ui).port.clone(), | ||||||
| 		flag_ui_interface: String = "local", | 		flag_ui_interface: String = "local", | ||||||
| 			or |c: &Config| otry!(c.ui).interface.clone(), | 			or |c: &Config| otry!(c.ui).interface.clone(), | ||||||
| 		flag_ui_path: String = "$DATA/signer", | 		flag_ui_path: String = "$BASE/signer", | ||||||
| 			or |c: &Config| otry!(c.ui).path.clone(), | 			or |c: &Config| otry!(c.ui).path.clone(), | ||||||
| 		// NOTE [todr] For security reasons don't put this to config files
 | 		// NOTE [todr] For security reasons don't put this to config files
 | ||||||
| 		flag_ui_no_validation: bool = false, or |_| None, | 		flag_ui_no_validation: bool = false, or |_| None, | ||||||
| @ -162,7 +167,7 @@ usage! { | |||||||
| 		// IPC
 | 		// IPC
 | ||||||
| 		flag_no_ipc: bool = false, | 		flag_no_ipc: bool = false, | ||||||
| 			or |c: &Config| otry!(c.ipc).disable.clone(), | 			or |c: &Config| otry!(c.ipc).disable.clone(), | ||||||
| 		flag_ipc_path: String = "$DATA/jsonrpc.ipc", | 		flag_ipc_path: String = "$BASE/jsonrpc.ipc", | ||||||
| 			or |c: &Config| otry!(c.ipc).path.clone(), | 			or |c: &Config| otry!(c.ipc).path.clone(), | ||||||
| 		flag_ipc_apis: String = "web3,eth,net,parity,parity_accounts,traces,rpc", | 		flag_ipc_apis: String = "web3,eth,net,parity,parity_accounts,traces,rpc", | ||||||
| 			or |c: &Config| otry!(c.ipc).apis.clone().map(|vec| vec.join(",")), | 			or |c: &Config| otry!(c.ipc).apis.clone().map(|vec| vec.join(",")), | ||||||
| @ -176,7 +181,7 @@ usage! { | |||||||
| 			or |c: &Config| otry!(c.dapps).interface.clone(), | 			or |c: &Config| otry!(c.dapps).interface.clone(), | ||||||
| 		flag_dapps_hosts: String = "none", | 		flag_dapps_hosts: String = "none", | ||||||
| 			or |c: &Config| otry!(c.dapps).hosts.clone().map(|vec| vec.join(",")), | 			or |c: &Config| otry!(c.dapps).hosts.clone().map(|vec| vec.join(",")), | ||||||
| 		flag_dapps_path: String = "$DATA/dapps", | 		flag_dapps_path: String = "$BASE/dapps", | ||||||
| 			or |c: &Config| otry!(c.dapps).path.clone(), | 			or |c: &Config| otry!(c.dapps).path.clone(), | ||||||
| 		flag_dapps_user: Option<String> = None, | 		flag_dapps_user: Option<String> = None, | ||||||
| 			or |c: &Config| otry!(c.dapps).user.clone().map(Some), | 			or |c: &Config| otry!(c.dapps).user.clone().map(Some), | ||||||
| @ -277,7 +282,7 @@ usage! { | |||||||
| 			or |c: &Config| otry!(c.vm).jit.clone(), | 			or |c: &Config| otry!(c.vm).jit.clone(), | ||||||
| 
 | 
 | ||||||
| 		// -- Miscellaneous Options
 | 		// -- Miscellaneous Options
 | ||||||
| 		flag_config: String = "$DATA/config.toml", or |_| None, | 		flag_config: String = "$BASE/config.toml", or |_| None, | ||||||
| 		flag_logging: Option<String> = None, | 		flag_logging: Option<String> = None, | ||||||
| 			or |c: &Config| otry!(c.misc).logging.clone().map(Some), | 			or |c: &Config| otry!(c.misc).logging.clone().map(Some), | ||||||
| 		flag_log_file: Option<String> = None, | 		flag_log_file: Option<String> = None, | ||||||
| @ -309,7 +314,12 @@ 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>, | ||||||
|  | 	base_path: Option<String>, | ||||||
| 	db_path: Option<String>, | 	db_path: Option<String>, | ||||||
| 	keys_path: Option<String>, | 	keys_path: Option<String>, | ||||||
| 	identity: Option<String>, | 	identity: Option<String>, | ||||||
| @ -533,8 +543,13 @@ 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_base_path: "$HOME/.parity".into(), | ||||||
|  | 			flag_db_path: "$HOME/.parity/chains".into(), | ||||||
| 			flag_keys_path: "$HOME/.parity/keys".into(), | 			flag_keys_path: "$HOME/.parity/keys".into(), | ||||||
| 			flag_identity: "".into(), | 			flag_identity: "".into(), | ||||||
| 
 | 
 | ||||||
| @ -676,7 +691,7 @@ mod tests { | |||||||
| 
 | 
 | ||||||
| 			// -- Miscellaneous Options
 | 			// -- Miscellaneous Options
 | ||||||
| 			flag_version: false, | 			flag_version: false, | ||||||
| 			flag_config: "$DATA/config.toml".into(), | 			flag_config: "$BASE/config.toml".into(), | ||||||
| 			flag_logging: Some("own_tx=trace".into()), | 			flag_logging: Some("own_tx=trace".into()), | ||||||
| 			flag_log_file: Some("/var/log/parity.log".into()), | 			flag_log_file: Some("/var/log/parity.log".into()), | ||||||
| 			flag_no_color: false, | 			flag_no_color: false, | ||||||
| @ -707,7 +722,12 @@ 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()), | ||||||
|  | 				base_path: None, | ||||||
| 				db_path: None, | 				db_path: None, | ||||||
| 				keys_path: None, | 				keys_path: None, | ||||||
| 				identity: None, | 				identity: None, | ||||||
|  | |||||||
| @ -34,11 +34,34 @@ 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, | ||||||
|                            testnet or dev (default: {flag_chain}). |                            testnet or dev (default: {flag_chain}). | ||||||
|   -d --db-path PATH        Specify the database & configuration directory path |   -d --base-path PATH      Specify the base data storage path. | ||||||
|  |                            (default: {flag_base_path}). | ||||||
|  |   --db-path PATH           Specify the database directory path | ||||||
|                            (default: {flag_db_path}). |                            (default: {flag_db_path}). | ||||||
|   --keys-path PATH         Specify the path for JSON key files to be found |   --keys-path PATH         Specify the path for JSON key files to be found | ||||||
|                            (default: {flag_keys_path}). |                            (default: {flag_keys_path}). | ||||||
| @ -339,6 +362,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}) | ||||||
|  | |||||||
| @ -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, | ||||||
| @ -589,7 +592,7 @@ impl Configuration { | |||||||
| 		ret.snapshot_peers = self.snapshot_peers(); | 		ret.snapshot_peers = self.snapshot_peers(); | ||||||
| 		ret.allow_ips = try!(self.allow_ips()); | 		ret.allow_ips = try!(self.allow_ips()); | ||||||
| 		ret.max_pending_peers = self.max_pending_peers(); | 		ret.max_pending_peers = self.max_pending_peers(); | ||||||
| 		let mut net_path = PathBuf::from(self.directories().data); | 		let mut net_path = PathBuf::from(self.directories().base); | ||||||
| 		net_path.push("network"); | 		net_path.push("network"); | ||||||
| 		ret.config_path = Some(net_path.to_str().unwrap().to_owned()); | 		ret.config_path = Some(net_path.to_str().unwrap().to_owned()); | ||||||
| 		ret.reserved_nodes = try!(self.init_reserved_nodes()); | 		ret.reserved_nodes = try!(self.init_reserved_nodes()); | ||||||
| @ -680,11 +683,34 @@ 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; | ||||||
| 
 | 
 | ||||||
| 		let data_path = replace_home("", self.args.flag_datadir.as_ref().unwrap_or(&self.args.flag_db_path)); | 		let data_path = replace_home("", self.args.flag_datadir.as_ref().unwrap_or(&self.args.flag_base_path)); | ||||||
| 
 | 
 | ||||||
|  | 		let db_path = replace_home(&data_path, &self.args.flag_db_path); | ||||||
| 		let keys_path = replace_home(&data_path, &self.args.flag_keys_path); | 		let keys_path = replace_home(&data_path, &self.args.flag_keys_path); | ||||||
| 		let dapps_path = replace_home(&data_path, &self.args.flag_dapps_path); | 		let dapps_path = replace_home(&data_path, &self.args.flag_dapps_path); | ||||||
| 		let ui_path = replace_home(&data_path, &self.args.flag_ui_path); | 		let ui_path = replace_home(&data_path, &self.args.flag_ui_path); | ||||||
| @ -706,7 +732,8 @@ impl Configuration { | |||||||
| 
 | 
 | ||||||
| 		Directories { | 		Directories { | ||||||
| 			keys: keys_path, | 			keys: keys_path, | ||||||
| 			data: data_path, | 			base: data_path, | ||||||
|  | 			db: db_path, | ||||||
| 			dapps: dapps_path, | 			dapps: dapps_path, | ||||||
| 			signer: ui_path, | 			signer: ui_path, | ||||||
| 		} | 		} | ||||||
| @ -716,7 +743,7 @@ impl Configuration { | |||||||
| 		if self.args.flag_geth { | 		if self.args.flag_geth { | ||||||
| 			geth_ipc_path(self.args.flag_testnet) | 			geth_ipc_path(self.args.flag_testnet) | ||||||
| 		} else { | 		} else { | ||||||
| 			parity_ipc_path(&self.directories().data, &self.args.flag_ipcpath.clone().unwrap_or(self.args.flag_ipc_path.clone())) | 			parity_ipc_path(&self.directories().base, &self.args.flag_ipcpath.clone().unwrap_or(self.args.flag_ipc_path.clone())) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -786,13 +813,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 +1014,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 +1058,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
 | ||||||
|  | |||||||
| @ -43,7 +43,7 @@ impl Default for Configuration { | |||||||
| 			hosts: Some(Vec::new()), | 			hosts: Some(Vec::new()), | ||||||
| 			user: None, | 			user: None, | ||||||
| 			pass: None, | 			pass: None, | ||||||
| 			dapps_path: replace_home(&data_dir, "$DATA/dapps"), | 			dapps_path: replace_home(&data_dir, "$BASE/dapps"), | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -27,7 +27,8 @@ const LEGACY_CLIENT_DB_VER_STR: &'static str = "5.3"; | |||||||
| 
 | 
 | ||||||
| #[derive(Debug, PartialEq)] | #[derive(Debug, PartialEq)] | ||||||
| pub struct Directories { | pub struct Directories { | ||||||
| 	pub data: String, | 	pub base: String, | ||||||
|  | 	pub db: String, | ||||||
| 	pub keys: String, | 	pub keys: String, | ||||||
| 	pub signer: String, | 	pub signer: String, | ||||||
| 	pub dapps: String, | 	pub dapps: String, | ||||||
| @ -37,17 +38,19 @@ impl Default for Directories { | |||||||
| 	fn default() -> Self { | 	fn default() -> Self { | ||||||
| 		let data_dir = default_data_path(); | 		let data_dir = default_data_path(); | ||||||
| 		Directories { | 		Directories { | ||||||
| 			data: replace_home(&data_dir, "$DATA"), | 			base: replace_home(&data_dir, "$BASE"), | ||||||
| 			keys: replace_home(&data_dir, "$DATA/keys"), | 			db: replace_home(&data_dir, "$BASE/chains"), | ||||||
| 			signer: replace_home(&data_dir, "$DATA/signer"), | 			keys: replace_home(&data_dir, "$BASE/keys"), | ||||||
| 			dapps: replace_home(&data_dir, "$DATA/dapps"), | 			signer: replace_home(&data_dir, "$BASE/signer"), | ||||||
|  | 			dapps: replace_home(&data_dir, "$BASE/dapps"), | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Directories { | impl Directories { | ||||||
| 	pub fn create_dirs(&self, dapps_enabled: bool, signer_enabled: bool) -> Result<(), String> { | 	pub fn create_dirs(&self, dapps_enabled: bool, signer_enabled: bool) -> Result<(), String> { | ||||||
| 		try!(fs::create_dir_all(&self.data).map_err(|e| e.to_string())); | 		try!(fs::create_dir_all(&self.base).map_err(|e| e.to_string())); | ||||||
|  | 		try!(fs::create_dir_all(&self.db).map_err(|e| e.to_string())); | ||||||
| 		try!(fs::create_dir_all(&self.keys).map_err(|e| e.to_string())); | 		try!(fs::create_dir_all(&self.keys).map_err(|e| e.to_string())); | ||||||
| 		if signer_enabled { | 		if signer_enabled { | ||||||
| 			try!(fs::create_dir_all(&self.signer).map_err(|e| e.to_string())); | 			try!(fs::create_dir_all(&self.signer).map_err(|e| e.to_string())); | ||||||
| @ -61,7 +64,8 @@ impl Directories { | |||||||
| 	/// Database paths.
 | 	/// Database paths.
 | ||||||
| 	pub fn database(&self, genesis_hash: H256, fork_name: Option<String>, spec_name: String) -> DatabaseDirectories { | 	pub fn database(&self, genesis_hash: H256, fork_name: Option<String>, spec_name: String) -> DatabaseDirectories { | ||||||
| 		DatabaseDirectories { | 		DatabaseDirectories { | ||||||
| 			path: self.data.clone(), | 			path: self.db.clone(), | ||||||
|  | 			legacy_path: self.base.clone(), | ||||||
| 			genesis_hash: genesis_hash, | 			genesis_hash: genesis_hash, | ||||||
| 			fork_name: fork_name, | 			fork_name: fork_name, | ||||||
| 			spec_name: spec_name, | 			spec_name: spec_name, | ||||||
| @ -70,14 +74,14 @@ impl Directories { | |||||||
| 
 | 
 | ||||||
| 	/// Get the ipc sockets path
 | 	/// Get the ipc sockets path
 | ||||||
| 	pub fn ipc_path(&self) -> PathBuf { | 	pub fn ipc_path(&self) -> PathBuf { | ||||||
| 		let mut dir = Path::new(&self.data).to_path_buf(); | 		let mut dir = Path::new(&self.base).to_path_buf(); | ||||||
| 		dir.push("ipc"); | 		dir.push("ipc"); | ||||||
| 		dir | 		dir | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// TODO: remove in 1.7
 | 	// TODO: remove in 1.7
 | ||||||
| 	pub fn legacy_keys_path(&self, testnet: bool) -> PathBuf { | 	pub fn legacy_keys_path(&self, testnet: bool) -> PathBuf { | ||||||
| 		let mut dir = Path::new(&self.data).to_path_buf(); | 		let mut dir = Path::new(&self.base).to_path_buf(); | ||||||
| 		if testnet { | 		if testnet { | ||||||
| 			dir.push("testnet_keys"); | 			dir.push("testnet_keys"); | ||||||
| 		} else { | 		} else { | ||||||
| @ -96,6 +100,7 @@ impl Directories { | |||||||
| #[derive(Debug, PartialEq)] | #[derive(Debug, PartialEq)] | ||||||
| pub struct DatabaseDirectories { | pub struct DatabaseDirectories { | ||||||
| 	pub path: String, | 	pub path: String, | ||||||
|  | 	pub legacy_path: String, | ||||||
| 	pub genesis_hash: H256, | 	pub genesis_hash: H256, | ||||||
| 	pub fork_name: Option<String>, | 	pub fork_name: Option<String>, | ||||||
| 	pub spec_name: String, | 	pub spec_name: String, | ||||||
| @ -105,14 +110,13 @@ impl DatabaseDirectories { | |||||||
| 	/// Base DB directory for the given fork.
 | 	/// Base DB directory for the given fork.
 | ||||||
| 	// TODO: remove in 1.7
 | 	// TODO: remove in 1.7
 | ||||||
| 	pub fn legacy_fork_path(&self) -> PathBuf { | 	pub fn legacy_fork_path(&self) -> PathBuf { | ||||||
| 		let mut dir = Path::new(&self.path).to_path_buf(); | 		let mut dir = Path::new(&self.legacy_path).to_path_buf(); | ||||||
| 		dir.push(format!("{:?}{}", H64::from(self.genesis_hash), self.fork_name.as_ref().map(|f| format!("-{}", f)).unwrap_or_default())); | 		dir.push(format!("{:?}{}", H64::from(self.genesis_hash), self.fork_name.as_ref().map(|f| format!("-{}", f)).unwrap_or_default())); | ||||||
| 		dir | 		dir | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	pub fn spec_root_path(&self) -> PathBuf { | 	pub fn spec_root_path(&self) -> PathBuf { | ||||||
| 		let mut dir = Path::new(&self.path).to_path_buf(); | 		let mut dir = Path::new(&self.path).to_path_buf(); | ||||||
| 		dir.push("chains"); |  | ||||||
| 		dir.push(&self.spec_name); | 		dir.push(&self.spec_name); | ||||||
| 		dir | 		dir | ||||||
| 	} | 	} | ||||||
| @ -195,6 +199,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; | ||||||
| @ -204,10 +213,11 @@ mod tests { | |||||||
| 	fn test_default_directories() { | 	fn test_default_directories() { | ||||||
| 		let data_dir = super::default_data_path(); | 		let data_dir = super::default_data_path(); | ||||||
| 		let expected = Directories { | 		let expected = Directories { | ||||||
| 			data: replace_home(&data_dir, "$DATA"), | 			base: replace_home(&data_dir, "$BASE"), | ||||||
| 			keys: replace_home(&data_dir, "$DATA/keys"), | 			db: replace_home(&data_dir, "$BASE/chains"), | ||||||
| 			signer: replace_home(&data_dir, "$DATA/signer"), | 			keys: replace_home(&data_dir, "$BASE/keys"), | ||||||
| 			dapps: replace_home(&data_dir, "$DATA/dapps"), | 			signer: replace_home(&data_dir, "$BASE/signer"), | ||||||
|  | 			dapps: replace_home(&data_dir, "$BASE/dapps"), | ||||||
| 		}; | 		}; | ||||||
| 		assert_eq!(expected, Directories::default()); | 		assert_eq!(expected, Directories::default()); | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -135,7 +135,7 @@ pub fn to_price(s: &str) -> Result<f32, String> { | |||||||
| pub fn replace_home(base: &str, arg: &str) -> String { | pub fn replace_home(base: &str, arg: &str) -> String { | ||||||
| 	// the $HOME directory on mac os should be `~/Library` or `~/Library/Application Support`
 | 	// the $HOME directory on mac os should be `~/Library` or `~/Library/Application Support`
 | ||||||
| 	let r = arg.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()); | 	let r = arg.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()); | ||||||
| 	let r = r.replace("$DATA", base	); | 	let r = r.replace("$BASE", base	); | ||||||
| 	r.replace("/", &::std::path::MAIN_SEPARATOR.to_string()	) | 	r.replace("/", &::std::path::MAIN_SEPARATOR.to_string()	) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -188,7 +188,7 @@ pub fn to_bootnodes(bootnodes: &Option<String>) -> Result<Vec<String>, String> { | |||||||
| pub fn default_network_config() -> ::ethsync::NetworkConfiguration { | pub fn default_network_config() -> ::ethsync::NetworkConfiguration { | ||||||
| 	use ethsync::{NetworkConfiguration, AllowIP}; | 	use ethsync::{NetworkConfiguration, AllowIP}; | ||||||
| 	NetworkConfiguration { | 	NetworkConfiguration { | ||||||
| 		config_path: Some(replace_home(&::dir::default_data_path(), "$DATA/network")), | 		config_path: Some(replace_home(&::dir::default_data_path(), "$BASE/network")), | ||||||
| 		net_config_path: None, | 		net_config_path: None, | ||||||
| 		listen_address: Some("0.0.0.0:30303".into()), | 		listen_address: Some("0.0.0.0:30303".into()), | ||||||
| 		public_address: None, | 		public_address: None, | ||||||
| @ -257,12 +257,13 @@ pub fn to_client_config( | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn execute_upgrades( | pub fn execute_upgrades( | ||||||
|  | 	base_path: &str, | ||||||
| 	dirs: &DatabaseDirectories, | 	dirs: &DatabaseDirectories, | ||||||
| 	pruning: Algorithm, | 	pruning: Algorithm, | ||||||
| 	compaction_profile: CompactionProfile | 	compaction_profile: CompactionProfile | ||||||
| ) -> Result<(), String> { | ) -> Result<(), String> { | ||||||
| 
 | 
 | ||||||
| 	upgrade_data_paths(dirs, pruning); | 	upgrade_data_paths(base_path, dirs, pruning); | ||||||
| 
 | 
 | ||||||
| 	match upgrade(Some(&dirs.path)) { | 	match upgrade(Some(&dirs.path)) { | ||||||
| 		Ok(upgrades_applied) if upgrades_applied > 0 => { | 		Ok(upgrades_applied) if upgrades_applied > 0 => { | ||||||
|  | |||||||
| @ -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(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | |||||||
| @ -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() |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
							
								
								
									
										183
									
								
								parity/main.rs
									
									
									
									
									
								
							
							
						
						
									
										183
									
								
								parity/main.rs
									
									
									
									
									
								
							| @ -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)); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -62,7 +62,7 @@ impl Default for IpcConfiguration { | |||||||
| 		let data_dir = default_data_path(); | 		let data_dir = default_data_path(); | ||||||
| 		IpcConfiguration { | 		IpcConfiguration { | ||||||
| 			enabled: true, | 			enabled: true, | ||||||
| 			socket_addr: parity_ipc_path(&data_dir, "$DATA/jsonrpc.ipc"), | 			socket_addr: parity_ipc_path(&data_dir, "$BASE/jsonrpc.ipc"), | ||||||
| 			apis: ApiSet::IpcContext, | 			apis: ApiSet::IpcContext, | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -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()) | ||||||
|  | |||||||
| @ -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,12 +160,15 @@ 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(); | ||||||
| 
 | 
 | ||||||
| 	// execute upgrades
 | 	// execute upgrades
 | ||||||
| 	try!(execute_upgrades(&db_dirs, algorithm, cmd.compaction.compaction_profile(db_dirs.db_root_path().as_path()))); | 	try!(execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, cmd.compaction.compaction_profile(db_dirs.db_root_path().as_path()))); | ||||||
| 
 | 
 | ||||||
| 	// create dirs used by parity
 | 	// create dirs used by parity
 | ||||||
| 	try!(cmd.dirs.create_dirs(cmd.dapps_conf.enabled, cmd.signer_conf.enabled)); | 	try!(cmd.dirs.create_dirs(cmd.dapps_conf.enabled, cmd.signer_conf.enabled)); | ||||||
| @ -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 | ||||||
| } | } | ||||||
|  | |||||||
| @ -44,7 +44,7 @@ impl Default for Configuration { | |||||||
| 			enabled: true, | 			enabled: true, | ||||||
| 			port: 8180, | 			port: 8180, | ||||||
| 			interface: "127.0.0.1".into(), | 			interface: "127.0.0.1".into(), | ||||||
| 			signer_path: replace_home(&data_dir, "$DATA/signer"), | 			signer_path: replace_home(&data_dir, "$BASE/signer"), | ||||||
| 			skip_origin_validation: false, | 			skip_origin_validation: false, | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -167,7 +167,7 @@ impl SnapshotCommand { | |||||||
| 		let snapshot_path = db_dirs.snapshot_path(); | 		let snapshot_path = db_dirs.snapshot_path(); | ||||||
| 
 | 
 | ||||||
| 		// execute upgrades
 | 		// execute upgrades
 | ||||||
| 		try!(execute_upgrades(&db_dirs, algorithm, self.compaction.compaction_profile(db_dirs.db_root_path().as_path()))); | 		try!(execute_upgrades(&self.dirs.base, &db_dirs, algorithm, self.compaction.compaction_profile(db_dirs.db_root_path().as_path()))); | ||||||
| 
 | 
 | ||||||
| 		// prepare client config
 | 		// prepare client config
 | ||||||
| 		let client_config = to_client_config(&self.cache_config, Mode::Active, tracing, fat_db, self.compaction, self.wal, VMType::default(), "".into(), algorithm, self.pruning_history, true); | 		let client_config = to_client_config(&self.cache_config, Mode::Active, tracing, fat_db, self.compaction, self.wal, VMType::default(), "".into(), algorithm, self.pruning_history, true); | ||||||
|  | |||||||
| @ -200,11 +200,11 @@ fn upgrade_user_defaults(dirs: &DatabaseDirectories) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn upgrade_data_paths(dirs: &DatabaseDirectories, pruning: Algorithm) { | pub fn upgrade_data_paths(base_path: &str, dirs: &DatabaseDirectories, pruning: Algorithm) { | ||||||
| 	let legacy_root_path = replace_home("", "$HOME/.parity"); | 	let legacy_root_path = replace_home("", "$HOME/.parity"); | ||||||
| 	let default_path = default_data_path(); | 	let default_path = default_data_path(); | ||||||
| 	if legacy_root_path != dirs.path && dirs.path == default_path { | 	if legacy_root_path != base_path && base_path == default_path { | ||||||
| 		upgrade_dir_location(&PathBuf::from(legacy_root_path), &PathBuf::from(&dirs.path)); | 		upgrade_dir_location(&PathBuf::from(legacy_root_path), &PathBuf::from(&base_path)); | ||||||
| 	} | 	} | ||||||
| 	upgrade_dir_location(&dirs.legacy_version_path(pruning), &dirs.db_path(pruning)); | 	upgrade_dir_location(&dirs.legacy_version_path(pruning), &dirs.db_path(pruning)); | ||||||
| 	upgrade_dir_location(&dirs.legacy_snapshot_path(), &dirs.snapshot_path()); | 	upgrade_dir_location(&dirs.legacy_snapshot_path(), &dirs.snapshot_path()); | ||||||
|  | |||||||
| @ -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 } | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
| @ -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()); | ||||||
| @ -359,4 +367,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)) | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -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()) | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -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; | ||||||
							
								
								
									
										97
									
								
								rpc/src/v1/tests/helpers/update_service.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								rpc/src/v1/tests/helpers/update_service.rs
									
									
									
									
									
										Normal 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, | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | } | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user