diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1d152114c..94ac69d2c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -8,7 +8,6 @@ variables: RUST_BACKTRACE: "1" RUSTFLAGS: "" CARGOFLAGS: "" - NIGHTLY: "nigtly" cache: key: "$CI_BUILD_STAGE/$CI_BUILD_REF_NAME" untracked: true @@ -21,7 +20,7 @@ linux-stable: - stable - triggers script: - - cargo build --release $CARGOFLAGS + - cargo build -j $(nproc) --release $CARGOFLAGS - strip target/release/parity - md5sum target/release/parity > parity.md5 - sh scripts/deb-build.sh amd64 @@ -31,10 +30,12 @@ linux-stable: - md5sum "parity_"$VER"_amd64.deb" > "parity_"$VER"_amd64.deb.md5" - aws configure set aws_access_key_id $s3_key - aws configure set aws_secret_access_key $s3_secret - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/parity --body target/release/parity - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/parity.md5 --body parity.md5 - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/"parity_"$VER"_amd64.deb" --body "parity_"$VER"_amd64.deb" - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/"parity_"$VER"_amd64.deb.md5" --body "parity_"$VER"_amd64.deb.md5" + - 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-linux-gnu + - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/parity --body target/release/parity + - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/parity.md5 --body parity.md5 + - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/"parity_"$VER"_amd64.deb" --body "parity_"$VER"_amd64.deb" + - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/x86_64-unknown-linux-gnu/"parity_"$VER"_amd64.deb.md5" --body "parity_"$VER"_amd64.deb.md5" tags: - rust - rust-stable @@ -51,7 +52,7 @@ linux-beta: - stable - triggers script: - - cargo build --release $CARGOFLAGS + - cargo build -j $(nproc) --release $CARGOFLAGS - strip target/release/parity tags: - rust @@ -70,7 +71,7 @@ linux-nightly: - stable - triggers script: - - cargo build --release $CARGOFLAGS + - cargo build -j $(nproc) --release $CARGOFLAGS - strip target/release/parity tags: - rust @@ -91,11 +92,13 @@ linux-centos: script: - export CXX="g++" - export CC="gcc" - - cargo build --release $CARGOFLAGS + - cargo build -j $(nproc) --release $CARGOFLAGS - strip target/release/parity - md5sum target/release/parity > parity.md5 - aws configure set aws_access_key_id $s3_key - aws configure set aws_secret_access_key $s3_secret + - if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable)$ ]]; then export S3_BUCKET=builds-parity-published; else export S3_BUCKET=builds-parity; fi + - aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/parity --body target/release/parity - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-unknown-centos-gnu/parity.md5 --body parity.md5 tags: @@ -116,7 +119,7 @@ linux-i686: script: - export HOST_CC=gcc - export HOST_CXX=g++ - - cargo build --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 - md5sum target/i686-unknown-linux-gnu/release/parity > parity.md5 - sh scripts/deb-build.sh i386 @@ -126,10 +129,12 @@ linux-i686: - md5sum "parity_"$VER"_i386.deb" > "parity_"$VER"_i386.deb.md5" - aws configure set aws_access_key_id $s3_key - aws configure set aws_secret_access_key $s3_secret - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/i686-unknown-linux-gnu/parity --body target/i686-unknown-linux-gnu/release/parity - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/i686-unknown-linux-gnu/parity.md5 --body parity.md5 - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/i686-unknown-linux-gnu/"parity_"$VER"_i386.deb" --body "parity_"$VER"_i386.deb" - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/i686-unknown-linux-gnu/"parity_"$VER"_i386.deb.md5" --body "parity_"$VER"_i386.deb.md5" + - 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 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/i686-unknown-linux-gnu/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/i686-unknown-linux-gnu/"parity_"$VER"_i386.deb.md5" --body "parity_"$VER"_i386.deb.md5" tags: - rust - rust-i686 @@ -156,7 +161,7 @@ linux-armv7: - echo "[target.armv7-unknown-linux-gnueabihf]" >> .cargo/config - echo "linker= \"arm-linux-gnueabihf-gcc\"" >> .cargo/config - cat .cargo/config - - cargo build --target armv7-unknown-linux-gnueabihf --release $CARGOFLAGS + - cargo build -j $(nproc) --target armv7-unknown-linux-gnueabihf --release $CARGOFLAGS - arm-linux-gnueabihf-strip target/armv7-unknown-linux-gnueabihf/release/parity - md5sum target/armv7-unknown-linux-gnueabihf/release/parity > parity.md5 - sh scripts/deb-build.sh armhf @@ -166,10 +171,12 @@ linux-armv7: - md5sum "parity_"$VER"_armhf.deb" > "parity_"$VER"_armhf.deb.md5" - aws configure set aws_access_key_id $s3_key - aws configure set aws_secret_access_key $s3_secret - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/parity --body target/armv7-unknown-linux-gnueabihf/release/parity - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/parity.md5 --body parity.md5 - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/"parity_"$VER"_armhf.deb" --body "parity_"$VER"_armhf.deb" - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/"parity_"$VER"_armhf.deb.md5" --body "parity_"$VER"_armhf.deb.md5" + - if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable)$ ]]; then export S3_BUCKET=builds-parity-published; else export S3_BUCKET=builds-parity; fi + - aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf + - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/parity --body target/armv7-unknown-linux-gnueabihf/release/parity + - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/parity.md5 --body parity.md5 + - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/"parity_"$VER"_armhf.deb" --body "parity_"$VER"_armhf.deb" + - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/armv7-unknown-linux-gnueabihf/"parity_"$VER"_armhf.deb.md5" --body "parity_"$VER"_armhf.deb.md5" tags: - rust - rust-arm @@ -196,7 +203,7 @@ linux-arm: - echo "[target.arm-unknown-linux-gnueabihf]" >> .cargo/config - echo "linker= \"arm-linux-gnueabihf-gcc\"" >> .cargo/config - cat .cargo/config - - cargo build --target arm-unknown-linux-gnueabihf --release $CARGOFLAGS + - cargo build -j $(nproc) --target arm-unknown-linux-gnueabihf --release $CARGOFLAGS - arm-linux-gnueabihf-strip target/arm-unknown-linux-gnueabihf/release/parity - md5sum target/arm-unknown-linux-gnueabihf/release/parity > parity.md5 - sh scripts/deb-build.sh armhf @@ -206,10 +213,12 @@ linux-arm: - md5sum "parity_"$VER"_armhf.deb" > "parity_"$VER"_armhf.deb.md5" - aws configure set aws_access_key_id $s3_key - aws configure set aws_secret_access_key $s3_secret - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/parity --body target/arm-unknown-linux-gnueabihf/release/parity - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/parity.md5 --body parity.md5 - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/"parity_"$VER"_armhf.deb" --body "parity_"$VER"_armhf.deb" - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/"parity_"$VER"_armhf.deb.md5" --body "parity_"$VER"_armhf.deb.md5" + - if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable)$ ]]; then export S3_BUCKET=builds-parity-published; else export S3_BUCKET=builds-parity; fi + - aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf + - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/parity --body target/arm-unknown-linux-gnueabihf/release/parity + - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/parity.md5 --body parity.md5 + - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/"parity_"$VER"_armhf.deb" --body "parity_"$VER"_armhf.deb" + - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabihf/"parity_"$VER"_armhf.deb.md5" --body "parity_"$VER"_armhf.deb.md5" tags: - rust - rust-arm @@ -222,9 +231,9 @@ linux-armv6: stage: build image: ethcore/rust-armv6:latest only: - - beta - - tags - - stable +# - beta +# - tags +# - stable - triggers script: - export CC=arm-linux-gnueabi-gcc @@ -236,13 +245,15 @@ linux-armv6: - echo "[target.arm-unknown-linux-gnueabi]" >> .cargo/config - echo "linker= \"arm-linux-gnueabi-gcc\"" >> .cargo/config - cat .cargo/config - - cargo build --target arm-unknown-linux-gnueabi --release $CARGOFLAGS + - cargo build -j $(nproc) --target arm-unknown-linux-gnueabi --release $CARGOFLAGS - arm-linux-gnueabi-strip target/arm-unknown-linux-gnueabi/release/parity - md5sum target/arm-unknown-linux-gnueabi/release/parity > parity.md5 - aws configure set aws_access_key_id $s3_key - aws configure set aws_secret_access_key $s3_secret - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabi/parity --body target/arm-unknown-linux-gnueabi/release/parity - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabi/parity.md5 --body parity.md5 + - if [[ $CI_BUILD_REF_NAME =~ ^(master|beta|stable)$ ]]; then export S3_BUCKET=builds-parity-published; else export S3_BUCKET=builds-parity; fi + - aws s3 rm --recursive s3://$S3_BUCKET/$CI_BUILD_REF_NAME/arm-unknown-linux-gnueabi + - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabi/parity --body target/arm-unknown-linux-gnueabi/release/parity + - aws s3api put-object --bucket $S3_BUCKET --key $CI_BUILD_REF_NAME/arm-unknown-linux-gnueabi/parity.md5 --body parity.md5 tags: - rust - rust-arm @@ -269,7 +280,7 @@ linux-aarch64: - echo "[target.aarch64-unknown-linux-gnu]" >> .cargo/config - echo "linker= \"aarch64-linux-gnu-gcc\"" >> .cargo/config - cat .cargo/config - - cargo build --target aarch64-unknown-linux-gnu --release $CARGOFLAGS + - cargo build -j $(nproc) --target aarch64-unknown-linux-gnu --release $CARGOFLAGS - aarch64-linux-gnu-strip target/aarch64-unknown-linux-gnu/release/parity - md5sum target/aarch64-unknown-linux-gnu/release/parity > parity.md5 - sh scripts/deb-build.sh arm64 @@ -279,10 +290,12 @@ linux-aarch64: - md5sum "parity_"$VER"_arm64.deb" > "parity_"$VER"_arm64.deb.md5" - aws configure set aws_access_key_id $s3_key - aws configure set aws_secret_access_key $s3_secret - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/aarch64-unknown-linux-gnu/parity --body target/aarch64-unknown-linux-gnu/release/parity - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/aarch64-unknown-linux-gnu/parity.md5 --body parity.md5 - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/aarch64-unknown-linux-gnu/"parity_"$VER"_arm64.deb" --body "parity_"$VER"_arm64.deb" - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/aarch64-unknown-linux-gnu/"parity_"$VER"_arm64.deb.md5" --body "parity_"$VER"_arm64.deb.md5" + - 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 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_"$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" tags: - rust - rust-arm @@ -299,13 +312,22 @@ darwin: - stable - triggers script: - - cargo build --release $CARGOFLAGS + - cargo build -j 8 --release -p ethstore #$CARGOFLAGS + - cargo build -j 8 --release #$CARGOFLAGS - rm -rf parity.md5 - md5sum target/release/parity > parity.md5 + - packagesbuild -v mac/Parity.pkgproj + - 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" + - md5sum "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg" >> "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg.md5" - aws configure set aws_access_key_id $s3_key - aws configure set aws_secret_access_key $s3_secret - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-apple-darwin/parity --body target/release/parity - - aws s3api put-object --bucket builds-parity --key $CI_BUILD_REF_NAME/x86_64-apple-darwin/parity.md5 --body parity.md5 + - 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 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/x86_64-apple-darwin/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/x86_64-apple-darwin/"parity-"$VER"-osx-installer-EXPERIMENTAL.pkg.md5" --body "parity-"$VER"-osx-installer-EXPERIMENTAL.pkg.md5" tags: - osx artifacts: @@ -328,7 +350,7 @@ windows: - set RUST_BACKTRACE=1 - set RUSTFLAGS=%RUSTFLAGS% - rustup default stable-x86_64-pc-windows-msvc - - cargo build --release %CARGOFLAGS% + - cargo build -j 8 --release #%CARGOFLAGS% - 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 - signtool sign /f %keyfile% /p %certpass% target\release\parity.exe @@ -349,14 +371,20 @@ windows: - cd ..\.. - aws configure set aws_access_key_id %s3_key% - aws configure set aws_secret_access_key %s3_secret% - - aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.exe --body target\release\parity.exe - - aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.exe.md5 --body target\release\parity.exe.md5 - - aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.zip --body target\release\parity.zip - - aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.zip.md5 --body target\release\parity.zip.md5 - - aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/InstallParity.exe --body nsis\InstallParity.exe - - aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/InstallParity.exe.md5 --body nsis\InstallParity.exe.md5 - - aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/win-installer.zip --body nsis\win-installer.zip - - aws s3api put-object --bucket builds-parity --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/win-installer.zip.md5 --body nsis\win-installer.zip.md5 + - echo %CI_BUILD_REF_NAME% + - echo %CI_BUILD_REF_NAME% | findstr /R "master" >nul 2>&1 && set S3_BUCKET=builds-parity-published || set S3_BUCKET=builds-parity + - echo %CI_BUILD_REF_NAME% | findstr /R "beta" >nul 2>&1 && set S3_BUCKET=builds-parity-published || set S3_BUCKET=builds-parity + - echo %CI_BUILD_REF_NAME% | findstr /R "stable" >nul 2>&1 && set S3_BUCKET=builds-parity-published || set S3_BUCKET=builds-parity + - echo %S3_BUCKET% + - aws s3 rm --recursive s3://%S3_BUCKET%/%CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc + - aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.exe --body target\release\parity.exe + - aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.exe.md5 --body target\release\parity.exe.md5 + - aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.zip --body target\release\parity.zip + - aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/parity.zip.md5 --body target\release\parity.zip.md5 + - aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/InstallParity.exe --body nsis\InstallParity.exe + - aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/InstallParity.exe.md5 --body nsis\InstallParity.exe.md5 + - aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/win-installer.zip --body nsis\win-installer.zip + - aws s3api put-object --bucket %S3_BUCKET% --key %CI_BUILD_REF_NAME%/x86_64-pc-windows-msvc/win-installer.zip.md5 --body nsis\win-installer.zip.md5 tags: - rust-windows artifacts: @@ -385,7 +413,7 @@ test-windows: - git submodule update --init --recursive script: - set RUST_BACKTRACE=1 - - 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 + - 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 tags: - rust-windows allow_failure: true @@ -394,13 +422,28 @@ test-rust-stable: image: ethcore/rust:stable before_script: - git submodule update --init --recursive - - export JS_FILES_MODIFIED=$(git --no-pager diff --name-only CI_BUILD_REF CI_BUILD_REF@{1} | grep \.js | wc -l) + - export JS_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep \.js | wc -l) - echo $JS_FILES_MODIFIED - - if [ -z $JS_FILES_MODIFIED ]; then echo "skip js test"; fi + - if [ "$JS_FILES_MODIFIED" = 0 ]; then echo "skip js test"; else ./js/scripts/install-deps.sh;fi script: - export RUST_BACKTRACE=1 - echo $JS_FILES_MODIFIED - - if [ -z $JS_FILES_MODIFIED ]; then echo "skip js test"; else ./test.sh $CARGOFLAGS --no-release; fi + - if [ "$JS_FILES_MODIFIED" = 0 ]; then echo "skip js test"&./test.sh $CARGOFLAGS --no-release; else echo "skip rust test"&./js/scripts/lint.sh&./js/scripts/test.sh&./js/scripts/build.sh; fi + tags: + - rust + - rust-stable +js-test: + stage: test + image: ethcore/rust:stable + before_script: + - git submodule update --init --recursive + - export JS_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep \.js | wc -l) + - echo $JS_FILES_MODIFIED + - if [ "$JS_FILES_MODIFIED" = 0 ]; then echo "skip js test"; else ./js/scripts/install-deps.sh;fi + script: + - export RUST_BACKTRACE=1 + - echo $JS_FILES_MODIFIED + - if [ "$JS_FILES_MODIFIED" = 0 ]; then echo "skip js test"; else echo "skip rust test"&./js/scripts/lint.sh&./js/scripts/test.sh&./js/scripts/build.sh; fi tags: - rust - rust-stable @@ -411,13 +454,10 @@ test-rust-beta: image: ethcore/rust:beta before_script: - git submodule update --init --recursive - - export JS_FILES_MODIFIED=$(git --no-pager diff --name-only CI_BUILD_REF CI_BUILD_REF@{1} | grep \.js | wc -l) - - echo $JS_FILES_MODIFIED - - if [ -z $JS_FILES_MODIFIED ]; then echo "skip js test"; fi script: - export RUST_BACKTRACE=1 - echo $JS_FILES_MODIFIED - - if [ -z $JS_FILES_MODIFIED ]; then echo "skip js test"; else ./test.sh $CARGOFLAGS --no-release; fi + - ./test.sh $CARGOFLAGS --no-release tags: - rust - rust-beta @@ -429,28 +469,13 @@ test-rust-nightly: image: ethcore/rust:nightly before_script: - git submodule update --init --recursive - - export JS_FILES_MODIFIED=$(git --no-pager diff --name-only CI_BUILD_REF CI_BUILD_REF@{1} | grep \.js | wc -l) - - echo $JS_FILES_MODIFIED - - if [ -z $JS_FILES_MODIFIED ]; then echo "skip js test"; fi script: - export RUST_BACKTRACE=1 - - echo $JS_FILES_MODIFIED - - if [ -z $JS_FILES_MODIFIED ]; then echo "skip js test"; else ./test.sh $CARGOFLAGS --no-release; fi + - ./test.sh $CARGOFLAGS --no-release tags: - rust - rust-nightly allow_failure: true -js-tests: - stage: test - image: ethcore/rust:stable - before_script: - - ./js/scripts/install-deps.sh - script: - - ./js/scripts/lint.sh - - ./js/scripts/test.sh - - ./js/scripts/build.sh - tags: - - javascript-test js-release: stage: js-build only: @@ -459,9 +484,11 @@ js-release: - stable image: ethcore/rust:stable before_script: - - if [[ $NIGHTLY != "master" ]]; then ./js/scripts/install-deps.sh; fi + - export JS_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep \.js | wc -l) + - echo $JS_FILES_MODIFIED + - if [ "$JS_FILES_MODIFIED" = 0 ]; then echo "skip js build"; else ./js/scripts/install-deps.sh;fi script: - - if [[ $NIGHTLY != "master" ]]; then ./js/scripts/build.sh; fi - - if [[ $NIGHTLY != "master" ]]; then ./js/scripts/release.sh; fi + - echo $JS_FILES_MODIFIED + - if [ "$JS_FILES_MODIFIED" = 0 ]; then echo "skip js build"; else ./js/scripts/build.sh&&./js/scripts/release.sh; fi tags: - javascript diff --git a/Cargo.lock b/Cargo.lock index 5d421f6d2..fc0465527 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,7 +3,7 @@ name = "parity" version = "1.5.0" dependencies = [ "ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy 0.0.96 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 1.1.1 (git+https://github.com/ethcore/rust-ctrlc.git)", "daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)", @@ -146,15 +146,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "clippy" -version = "0.0.96" +version = "0.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "clippy_lints 0.0.96 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy_lints 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "clippy_lints" -version = "0.0.96" +version = "0.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -224,7 +224,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "elastic-array" version = "0.6.0" -source = "git+https://github.com/ethcore/elastic-array#70e4012e691b732c7c4cb04e9232799e6aa268bc" +source = "git+https://github.com/ethcore/elastic-array#346f1ba5982576dab9d0b8fa178b50e1db0a21cd" dependencies = [ "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -280,7 +280,7 @@ dependencies = [ "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy 0.0.96 (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)", "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.4.0", @@ -334,7 +334,7 @@ dependencies = [ name = "ethcore-dapps" version = "1.5.0" dependencies = [ - "clippy 0.0.96 (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)", "ethcore-devtools 1.4.0", "ethcore-hash-fetch 1.5.0", @@ -386,7 +386,7 @@ version = "1.5.0" dependencies = [ "crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.1 (git+https://github.com/carllerche/mio)", + "mio 0.6.1 (git+https://github.com/ethcore/mio)", "parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -476,7 +476,7 @@ dependencies = [ "igd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.1 (git+https://github.com/carllerche/mio)", + "mio 0.6.1 (git+https://github.com/ethcore/mio)", "parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.1.0", @@ -491,7 +491,7 @@ dependencies = [ name = "ethcore-rpc" version = "1.5.0" dependencies = [ - "clippy 0.0.96 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.4.0", "ethcore 1.5.0", "ethcore-devtools 1.4.0", @@ -521,7 +521,7 @@ dependencies = [ name = "ethcore-signer" version = "1.5.0" dependencies = [ - "clippy 0.0.96 (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)", "ethcore-devtools 1.4.0", "ethcore-io 1.5.0", @@ -560,7 +560,7 @@ version = "1.5.0" dependencies = [ "ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy 0.0.96 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.6.0 (git+https://github.com/ethcore/elastic-array)", "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)", @@ -650,7 +650,7 @@ dependencies = [ name = "ethsync" version = "1.5.0" dependencies = [ - "clippy 0.0.96 (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)", "ethcore 1.5.0", "ethcore-io 1.5.0", @@ -1027,7 +1027,7 @@ dependencies = [ [[package]] name = "mio" version = "0.6.1" -source = "git+https://github.com/carllerche/mio#56f8663510196fdca04bdf7c5f4d60b24297826f" +source = "git+https://github.com/ethcore/mio#ef182bae193a9c7457cd2cf661fcaffb226e3eef" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1264,7 +1264,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/ethcore/js-precompiled.git#587684374a12bf715151dd987a552a3d61e42972" +source = "git+https://github.com/ethcore/js-precompiled.git#a5a1c15f4d125654e1d1cdcb6b7f92a606f1d2d0" dependencies = [ "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2006,8 +2006,8 @@ dependencies = [ "checksum bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c129aff112dcc562970abb69e2508b40850dd24c274761bb50fb8a0067ba6c27" "checksum bytes 0.4.0-dev (git+https://github.com/carllerche/bytes)" = "" "checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c" -"checksum clippy 0.0.96 (registry+https://github.com/rust-lang/crates.io-index)" = "6eacf01b0aad84a0817703498f72d252df7c0faf6a5b86d0be4265f1829e459f" -"checksum clippy_lints 0.0.96 (registry+https://github.com/rust-lang/crates.io-index)" = "a49960c9aab544ce86b004dcb61620e8b898fea5fc0f697a028f460f48221ed6" +"checksum clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "5b4fabf979ddf6419a313c1c0ada4a5b95cfd2049c56e8418d622d27b4b6ff32" +"checksum clippy_lints 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "ce96ec05bfe018a0d5d43da115e54850ea2217981ff0f2e462780ab9d594651a" "checksum cookie 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90266f45846f14a1e986c77d1e9c2626b8c342ed806fe60241ec38cc8697b245" "checksum crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "fb974f835e90390c5f9dfac00f05b06dc117299f5ea4e85fbc7bb443af4911cc" "checksum ctrlc 1.1.1 (git+https://github.com/ethcore/rust-ctrlc.git)" = "" @@ -2054,7 +2054,7 @@ dependencies = [ "checksum mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)" = "" "checksum mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a637d1ca14eacae06296a008fa7ad955347e34efcb5891cfd8ba05491a37907e" "checksum mio 0.6.0-dev (git+https://github.com/ethcore/mio?branch=timer-fix)" = "" -"checksum mio 0.6.1 (git+https://github.com/carllerche/mio)" = "" +"checksum mio 0.6.1 (git+https://github.com/ethcore/mio)" = "" "checksum miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d5bfc6782530ac8ace97af10a540054a37126b63b0702ddaaa243b73b5745b9a" "checksum msdos_time 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c04b68cc63a8480fb2550343695f7be72effdec953a9d4508161c3e69041c7d8" "checksum nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)" = "" diff --git a/Cargo.toml b/Cargo.toml index a8d7ba794..3808cce95 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ ethcore-hash-fetch = { path = "ethcore/hash-fetch" } rlp = { path = "util/rlp" } ethcore-stratum = { path = "stratum" } ethcore-dapps = { path = "dapps", optional = true } -clippy = { version = "0.0.96", optional = true} +clippy = { version = "0.0.103", optional = true} [target.'cfg(windows)'.dependencies] winapi = "0.2" diff --git a/dapps/Cargo.toml b/dapps/Cargo.toml index 15e537820..6be30884a 100644 --- a/dapps/Cargo.toml +++ b/dapps/Cargo.toml @@ -34,7 +34,7 @@ ethcore-hash-fetch = { path = "../ethcore/hash-fetch" } fetch = { path = "../util/fetch" } parity-ui = { path = "./ui" } -clippy = { version = "0.0.96", optional = true} +clippy = { version = "0.0.103", optional = true} [build-dependencies] serde_codegen = { version = "0.8", optional = true } diff --git a/dapps/src/api/types.rs.in b/dapps/src/api/types.rs.in index 8bbefaa83..a95a0d446 100644 --- a/dapps/src/api/types.rs.in +++ b/dapps/src/api/types.rs.in @@ -17,6 +17,7 @@ use endpoint::EndpointInfo; #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] pub struct App { pub id: String, pub name: String, @@ -54,6 +55,7 @@ impl Into for App { } #[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] pub struct ApiError { pub code: String, pub title: String, diff --git a/db/Cargo.toml b/db/Cargo.toml index 27eadef4a..2b4a19892 100644 --- a/db/Cargo.toml +++ b/db/Cargo.toml @@ -11,7 +11,7 @@ build = "build.rs" ethcore-ipc-codegen = { path = "../ipc/codegen" } [dependencies] -clippy = { version = "0.0.96", optional = true} +clippy = { version = "0.0.103", optional = true} ethcore-devtools = { path = "../devtools" } ethcore-ipc = { path = "../ipc/rpc" } rocksdb = { git = "https://github.com/ethcore/rust-rocksdb" } diff --git a/docker/ubuntu-stable/Dockerfile b/docker/ubuntu-stable/Dockerfile index 2a8ee3da8..3fe36f32c 100644 --- a/docker/ubuntu-stable/Dockerfile +++ b/docker/ubuntu-stable/Dockerfile @@ -3,6 +3,7 @@ WORKDIR /build # install tools and dependencies RUN apt-get update && \ apt-get install -y \ + build-essential \ g++ \ curl \ git \ diff --git a/docker/ubuntu/Dockerfile b/docker/ubuntu/Dockerfile index 0c8e7d5db..e98c60daa 100644 --- a/docker/ubuntu/Dockerfile +++ b/docker/ubuntu/Dockerfile @@ -4,6 +4,7 @@ WORKDIR /build RUN apt-get update && \ apt-get install -y \ g++ \ + build-essential \ curl \ git \ file \ diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 07bf9cbff..713cc1045 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -29,7 +29,7 @@ byteorder = "0.5" transient-hashmap = "0.1" linked-hash-map = "0.3.0" evmjit = { path = "../evmjit", optional = true } -clippy = { version = "0.0.96", optional = true} +clippy = { version = "0.0.103", optional = true} ethash = { path = "../ethash" } ethcore-util = { path = "../util" } ethcore-io = { path = "../util/io" } diff --git a/ethcore/res/authority_round.json b/ethcore/res/authority_round.json index ad23b461f..9ab782395 100644 --- a/ethcore/res/authority_round.json +++ b/ethcore/res/authority_round.json @@ -21,8 +21,8 @@ "genesis": { "seal": { "generic": { - "fields": 1, - "rlp": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa" + "fields": 2, + "rlp": "0x200" } }, "difficulty": "0x20000", diff --git a/ethcore/res/ethereum/ropsten.json b/ethcore/res/ethereum/ropsten.json index c92676161..62282801d 100644 --- a/ethcore/res/ethereum/ropsten.json +++ b/ethcore/res/ethereum/ropsten.json @@ -8,7 +8,7 @@ "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", "blockReward": "0x4563918244F40000", - "registrar": "0x52dff57a8a1532e6afb3dc07e2af58bb9eb05b3d", + "registrar": "0x81a4b044831c4f12ba601adb9274516939e9b8a2", "homesteadTransition": 0, "eip150Transition": 0, "eip155Transition": 10, @@ -47,258 +47,258 @@ "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "0", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "0", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "0", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, - "0000000000000000000000000000000000000000": { "balance": "1" }, - "0000000000000000000000000000000000000005": { "balance": "1" }, - "0000000000000000000000000000000000000006": { "balance": "1" }, - "0000000000000000000000000000000000000007": { "balance": "1" }, - "0000000000000000000000000000000000000008": { "balance": "1" }, - "0000000000000000000000000000000000000009": { "balance": "1" }, - "000000000000000000000000000000000000000a": { "balance": "0" }, - "000000000000000000000000000000000000000b": { "balance": "0" }, - "000000000000000000000000000000000000000c": { "balance": "0" }, - "000000000000000000000000000000000000000d": { "balance": "0" }, - "000000000000000000000000000000000000000e": { "balance": "0" }, - "000000000000000000000000000000000000000f": { "balance": "0" }, - "0000000000000000000000000000000000000010": { "balance": "0" }, - "0000000000000000000000000000000000000011": { "balance": "0" }, - "0000000000000000000000000000000000000012": { "balance": "0" }, - "0000000000000000000000000000000000000013": { "balance": "0" }, - "0000000000000000000000000000000000000014": { "balance": "0" }, - "0000000000000000000000000000000000000015": { "balance": "0" }, - "0000000000000000000000000000000000000016": { "balance": "0" }, - "0000000000000000000000000000000000000017": { "balance": "0" }, - "0000000000000000000000000000000000000018": { "balance": "0" }, - "0000000000000000000000000000000000000019": { "balance": "0" }, - "000000000000000000000000000000000000001a": { "balance": "0" }, - "000000000000000000000000000000000000001b": { "balance": "0" }, - "000000000000000000000000000000000000001c": { "balance": "0" }, - "000000000000000000000000000000000000001d": { "balance": "0" }, - "000000000000000000000000000000000000001e": { "balance": "0" }, - "000000000000000000000000000000000000001f": { "balance": "0" }, - "0000000000000000000000000000000000000020": { "balance": "0" }, - "0000000000000000000000000000000000000021": { "balance": "0" }, - "0000000000000000000000000000000000000022": { "balance": "0" }, - "0000000000000000000000000000000000000023": { "balance": "0" }, - "0000000000000000000000000000000000000024": { "balance": "0" }, - "0000000000000000000000000000000000000025": { "balance": "0" }, - "0000000000000000000000000000000000000026": { "balance": "0" }, - "0000000000000000000000000000000000000027": { "balance": "0" }, - "0000000000000000000000000000000000000028": { "balance": "0" }, - "0000000000000000000000000000000000000029": { "balance": "0" }, - "000000000000000000000000000000000000002a": { "balance": "0" }, - "000000000000000000000000000000000000002b": { "balance": "0" }, - "000000000000000000000000000000000000002c": { "balance": "0" }, - "000000000000000000000000000000000000002d": { "balance": "0" }, - "000000000000000000000000000000000000002e": { "balance": "0" }, - "000000000000000000000000000000000000002f": { "balance": "0" }, - "0000000000000000000000000000000000000030": { "balance": "0" }, - "0000000000000000000000000000000000000031": { "balance": "0" }, - "0000000000000000000000000000000000000032": { "balance": "0" }, - "0000000000000000000000000000000000000033": { "balance": "0" }, - "0000000000000000000000000000000000000034": { "balance": "0" }, - "0000000000000000000000000000000000000035": { "balance": "0" }, - "0000000000000000000000000000000000000036": { "balance": "0" }, - "0000000000000000000000000000000000000037": { "balance": "0" }, - "0000000000000000000000000000000000000038": { "balance": "0" }, - "0000000000000000000000000000000000000039": { "balance": "0" }, - "000000000000000000000000000000000000003a": { "balance": "0" }, - "000000000000000000000000000000000000003b": { "balance": "0" }, - "000000000000000000000000000000000000003c": { "balance": "0" }, - "000000000000000000000000000000000000003d": { "balance": "0" }, - "000000000000000000000000000000000000003e": { "balance": "0" }, - "000000000000000000000000000000000000003f": { "balance": "0" }, - "0000000000000000000000000000000000000040": { "balance": "0" }, - "0000000000000000000000000000000000000041": { "balance": "0" }, - "0000000000000000000000000000000000000042": { "balance": "0" }, - "0000000000000000000000000000000000000043": { "balance": "0" }, - "0000000000000000000000000000000000000044": { "balance": "0" }, - "0000000000000000000000000000000000000045": { "balance": "0" }, - "0000000000000000000000000000000000000046": { "balance": "0" }, - "0000000000000000000000000000000000000047": { "balance": "0" }, - "0000000000000000000000000000000000000048": { "balance": "0" }, - "0000000000000000000000000000000000000049": { "balance": "0" }, - "000000000000000000000000000000000000004a": { "balance": "0" }, - "000000000000000000000000000000000000004b": { "balance": "0" }, - "000000000000000000000000000000000000004c": { "balance": "0" }, - "000000000000000000000000000000000000004d": { "balance": "0" }, - "000000000000000000000000000000000000004e": { "balance": "0" }, - "000000000000000000000000000000000000004f": { "balance": "0" }, - "0000000000000000000000000000000000000050": { "balance": "0" }, - "0000000000000000000000000000000000000051": { "balance": "0" }, - "0000000000000000000000000000000000000052": { "balance": "0" }, - "0000000000000000000000000000000000000053": { "balance": "0" }, - "0000000000000000000000000000000000000054": { "balance": "0" }, - "0000000000000000000000000000000000000055": { "balance": "0" }, - "0000000000000000000000000000000000000056": { "balance": "0" }, - "0000000000000000000000000000000000000057": { "balance": "0" }, - "0000000000000000000000000000000000000058": { "balance": "0" }, - "0000000000000000000000000000000000000059": { "balance": "0" }, - "000000000000000000000000000000000000005a": { "balance": "0" }, - "000000000000000000000000000000000000005b": { "balance": "0" }, - "000000000000000000000000000000000000005c": { "balance": "0" }, - "000000000000000000000000000000000000005d": { "balance": "0" }, - "000000000000000000000000000000000000005e": { "balance": "0" }, - "000000000000000000000000000000000000005f": { "balance": "0" }, - "0000000000000000000000000000000000000060": { "balance": "0" }, - "0000000000000000000000000000000000000061": { "balance": "0" }, - "0000000000000000000000000000000000000062": { "balance": "0" }, - "0000000000000000000000000000000000000063": { "balance": "0" }, - "0000000000000000000000000000000000000064": { "balance": "0" }, - "0000000000000000000000000000000000000065": { "balance": "0" }, - "0000000000000000000000000000000000000066": { "balance": "0" }, - "0000000000000000000000000000000000000067": { "balance": "0" }, - "0000000000000000000000000000000000000068": { "balance": "0" }, - "0000000000000000000000000000000000000069": { "balance": "0" }, - "000000000000000000000000000000000000006a": { "balance": "0" }, - "000000000000000000000000000000000000006b": { "balance": "0" }, - "000000000000000000000000000000000000006c": { "balance": "0" }, - "000000000000000000000000000000000000006d": { "balance": "0" }, - "000000000000000000000000000000000000006e": { "balance": "0" }, - "000000000000000000000000000000000000006f": { "balance": "0" }, - "0000000000000000000000000000000000000070": { "balance": "0" }, - "0000000000000000000000000000000000000071": { "balance": "0" }, - "0000000000000000000000000000000000000072": { "balance": "0" }, - "0000000000000000000000000000000000000073": { "balance": "0" }, - "0000000000000000000000000000000000000074": { "balance": "0" }, - "0000000000000000000000000000000000000075": { "balance": "0" }, - "0000000000000000000000000000000000000076": { "balance": "0" }, - "0000000000000000000000000000000000000077": { "balance": "0" }, - "0000000000000000000000000000000000000078": { "balance": "0" }, - "0000000000000000000000000000000000000079": { "balance": "0" }, - "000000000000000000000000000000000000007a": { "balance": "0" }, - "000000000000000000000000000000000000007b": { "balance": "0" }, - "000000000000000000000000000000000000007c": { "balance": "0" }, - "000000000000000000000000000000000000007d": { "balance": "0" }, - "000000000000000000000000000000000000007e": { "balance": "0" }, - "000000000000000000000000000000000000007f": { "balance": "0" }, - "0000000000000000000000000000000000000080": { "balance": "0" }, - "0000000000000000000000000000000000000081": { "balance": "0" }, - "0000000000000000000000000000000000000082": { "balance": "0" }, - "0000000000000000000000000000000000000083": { "balance": "0" }, - "0000000000000000000000000000000000000084": { "balance": "0" }, - "0000000000000000000000000000000000000085": { "balance": "0" }, - "0000000000000000000000000000000000000086": { "balance": "0" }, - "0000000000000000000000000000000000000087": { "balance": "0" }, - "0000000000000000000000000000000000000088": { "balance": "0" }, - "0000000000000000000000000000000000000089": { "balance": "0" }, - "000000000000000000000000000000000000008a": { "balance": "0" }, - "000000000000000000000000000000000000008b": { "balance": "0" }, - "000000000000000000000000000000000000008c": { "balance": "0" }, - "000000000000000000000000000000000000008d": { "balance": "0" }, - "000000000000000000000000000000000000008e": { "balance": "0" }, - "000000000000000000000000000000000000008f": { "balance": "0" }, - "0000000000000000000000000000000000000090": { "balance": "0" }, - "0000000000000000000000000000000000000091": { "balance": "0" }, - "0000000000000000000000000000000000000092": { "balance": "0" }, - "0000000000000000000000000000000000000093": { "balance": "0" }, - "0000000000000000000000000000000000000094": { "balance": "0" }, - "0000000000000000000000000000000000000095": { "balance": "0" }, - "0000000000000000000000000000000000000096": { "balance": "0" }, - "0000000000000000000000000000000000000097": { "balance": "0" }, - "0000000000000000000000000000000000000098": { "balance": "0" }, - "0000000000000000000000000000000000000099": { "balance": "0" }, - "000000000000000000000000000000000000009a": { "balance": "0" }, - "000000000000000000000000000000000000009b": { "balance": "0" }, - "000000000000000000000000000000000000009c": { "balance": "0" }, - "000000000000000000000000000000000000009d": { "balance": "0" }, - "000000000000000000000000000000000000009e": { "balance": "0" }, - "000000000000000000000000000000000000009f": { "balance": "0" }, - "00000000000000000000000000000000000000a0": { "balance": "0" }, - "00000000000000000000000000000000000000a1": { "balance": "0" }, - "00000000000000000000000000000000000000a2": { "balance": "0" }, - "00000000000000000000000000000000000000a3": { "balance": "0" }, - "00000000000000000000000000000000000000a4": { "balance": "0" }, - "00000000000000000000000000000000000000a5": { "balance": "0" }, - "00000000000000000000000000000000000000a6": { "balance": "0" }, - "00000000000000000000000000000000000000a7": { "balance": "0" }, - "00000000000000000000000000000000000000a8": { "balance": "0" }, - "00000000000000000000000000000000000000a9": { "balance": "0" }, - "00000000000000000000000000000000000000aa": { "balance": "0" }, - "00000000000000000000000000000000000000ab": { "balance": "0" }, - "00000000000000000000000000000000000000ac": { "balance": "0" }, - "00000000000000000000000000000000000000ad": { "balance": "0" }, - "00000000000000000000000000000000000000ae": { "balance": "0" }, - "00000000000000000000000000000000000000af": { "balance": "0" }, - "00000000000000000000000000000000000000b0": { "balance": "0" }, - "00000000000000000000000000000000000000b1": { "balance": "0" }, - "00000000000000000000000000000000000000b2": { "balance": "0" }, - "00000000000000000000000000000000000000b3": { "balance": "0" }, - "00000000000000000000000000000000000000b4": { "balance": "0" }, - "00000000000000000000000000000000000000b5": { "balance": "0" }, - "00000000000000000000000000000000000000b6": { "balance": "0" }, - "00000000000000000000000000000000000000b7": { "balance": "0" }, - "00000000000000000000000000000000000000b8": { "balance": "0" }, - "00000000000000000000000000000000000000b9": { "balance": "0" }, - "00000000000000000000000000000000000000ba": { "balance": "0" }, - "00000000000000000000000000000000000000bb": { "balance": "0" }, - "00000000000000000000000000000000000000bc": { "balance": "0" }, - "00000000000000000000000000000000000000bd": { "balance": "0" }, - "00000000000000000000000000000000000000be": { "balance": "0" }, - "00000000000000000000000000000000000000bf": { "balance": "0" }, - "00000000000000000000000000000000000000c0": { "balance": "0" }, - "00000000000000000000000000000000000000c1": { "balance": "0" }, - "00000000000000000000000000000000000000c2": { "balance": "0" }, - "00000000000000000000000000000000000000c3": { "balance": "0" }, - "00000000000000000000000000000000000000c4": { "balance": "0" }, - "00000000000000000000000000000000000000c5": { "balance": "0" }, - "00000000000000000000000000000000000000c6": { "balance": "0" }, - "00000000000000000000000000000000000000c7": { "balance": "0" }, - "00000000000000000000000000000000000000c8": { "balance": "0" }, - "00000000000000000000000000000000000000c9": { "balance": "0" }, - "00000000000000000000000000000000000000ca": { "balance": "0" }, - "00000000000000000000000000000000000000cb": { "balance": "0" }, - "00000000000000000000000000000000000000cc": { "balance": "0" }, - "00000000000000000000000000000000000000cd": { "balance": "0" }, - "00000000000000000000000000000000000000ce": { "balance": "0" }, - "00000000000000000000000000000000000000cf": { "balance": "0" }, - "00000000000000000000000000000000000000d0": { "balance": "0" }, - "00000000000000000000000000000000000000d1": { "balance": "0" }, - "00000000000000000000000000000000000000d2": { "balance": "0" }, - "00000000000000000000000000000000000000d3": { "balance": "0" }, - "00000000000000000000000000000000000000d4": { "balance": "0" }, - "00000000000000000000000000000000000000d5": { "balance": "0" }, - "00000000000000000000000000000000000000d6": { "balance": "0" }, - "00000000000000000000000000000000000000d7": { "balance": "0" }, - "00000000000000000000000000000000000000d8": { "balance": "0" }, - "00000000000000000000000000000000000000d9": { "balance": "0" }, + "0000000000000000000000000000000000000000": { "balance": "1" }, + "0000000000000000000000000000000000000005": { "balance": "1" }, + "0000000000000000000000000000000000000006": { "balance": "1" }, + "0000000000000000000000000000000000000007": { "balance": "1" }, + "0000000000000000000000000000000000000008": { "balance": "1" }, + "0000000000000000000000000000000000000009": { "balance": "1" }, + "000000000000000000000000000000000000000a": { "balance": "0" }, + "000000000000000000000000000000000000000b": { "balance": "0" }, + "000000000000000000000000000000000000000c": { "balance": "0" }, + "000000000000000000000000000000000000000d": { "balance": "0" }, + "000000000000000000000000000000000000000e": { "balance": "0" }, + "000000000000000000000000000000000000000f": { "balance": "0" }, + "0000000000000000000000000000000000000010": { "balance": "0" }, + "0000000000000000000000000000000000000011": { "balance": "0" }, + "0000000000000000000000000000000000000012": { "balance": "0" }, + "0000000000000000000000000000000000000013": { "balance": "0" }, + "0000000000000000000000000000000000000014": { "balance": "0" }, + "0000000000000000000000000000000000000015": { "balance": "0" }, + "0000000000000000000000000000000000000016": { "balance": "0" }, + "0000000000000000000000000000000000000017": { "balance": "0" }, + "0000000000000000000000000000000000000018": { "balance": "0" }, + "0000000000000000000000000000000000000019": { "balance": "0" }, + "000000000000000000000000000000000000001a": { "balance": "0" }, + "000000000000000000000000000000000000001b": { "balance": "0" }, + "000000000000000000000000000000000000001c": { "balance": "0" }, + "000000000000000000000000000000000000001d": { "balance": "0" }, + "000000000000000000000000000000000000001e": { "balance": "0" }, + "000000000000000000000000000000000000001f": { "balance": "0" }, + "0000000000000000000000000000000000000020": { "balance": "0" }, + "0000000000000000000000000000000000000021": { "balance": "0" }, + "0000000000000000000000000000000000000022": { "balance": "0" }, + "0000000000000000000000000000000000000023": { "balance": "0" }, + "0000000000000000000000000000000000000024": { "balance": "0" }, + "0000000000000000000000000000000000000025": { "balance": "0" }, + "0000000000000000000000000000000000000026": { "balance": "0" }, + "0000000000000000000000000000000000000027": { "balance": "0" }, + "0000000000000000000000000000000000000028": { "balance": "0" }, + "0000000000000000000000000000000000000029": { "balance": "0" }, + "000000000000000000000000000000000000002a": { "balance": "0" }, + "000000000000000000000000000000000000002b": { "balance": "0" }, + "000000000000000000000000000000000000002c": { "balance": "0" }, + "000000000000000000000000000000000000002d": { "balance": "0" }, + "000000000000000000000000000000000000002e": { "balance": "0" }, + "000000000000000000000000000000000000002f": { "balance": "0" }, + "0000000000000000000000000000000000000030": { "balance": "0" }, + "0000000000000000000000000000000000000031": { "balance": "0" }, + "0000000000000000000000000000000000000032": { "balance": "0" }, + "0000000000000000000000000000000000000033": { "balance": "0" }, + "0000000000000000000000000000000000000034": { "balance": "0" }, + "0000000000000000000000000000000000000035": { "balance": "0" }, + "0000000000000000000000000000000000000036": { "balance": "0" }, + "0000000000000000000000000000000000000037": { "balance": "0" }, + "0000000000000000000000000000000000000038": { "balance": "0" }, + "0000000000000000000000000000000000000039": { "balance": "0" }, + "000000000000000000000000000000000000003a": { "balance": "0" }, + "000000000000000000000000000000000000003b": { "balance": "0" }, + "000000000000000000000000000000000000003c": { "balance": "0" }, + "000000000000000000000000000000000000003d": { "balance": "0" }, + "000000000000000000000000000000000000003e": { "balance": "0" }, + "000000000000000000000000000000000000003f": { "balance": "0" }, + "0000000000000000000000000000000000000040": { "balance": "0" }, + "0000000000000000000000000000000000000041": { "balance": "0" }, + "0000000000000000000000000000000000000042": { "balance": "0" }, + "0000000000000000000000000000000000000043": { "balance": "0" }, + "0000000000000000000000000000000000000044": { "balance": "0" }, + "0000000000000000000000000000000000000045": { "balance": "0" }, + "0000000000000000000000000000000000000046": { "balance": "0" }, + "0000000000000000000000000000000000000047": { "balance": "0" }, + "0000000000000000000000000000000000000048": { "balance": "0" }, + "0000000000000000000000000000000000000049": { "balance": "0" }, + "000000000000000000000000000000000000004a": { "balance": "0" }, + "000000000000000000000000000000000000004b": { "balance": "0" }, + "000000000000000000000000000000000000004c": { "balance": "0" }, + "000000000000000000000000000000000000004d": { "balance": "0" }, + "000000000000000000000000000000000000004e": { "balance": "0" }, + "000000000000000000000000000000000000004f": { "balance": "0" }, + "0000000000000000000000000000000000000050": { "balance": "0" }, + "0000000000000000000000000000000000000051": { "balance": "0" }, + "0000000000000000000000000000000000000052": { "balance": "0" }, + "0000000000000000000000000000000000000053": { "balance": "0" }, + "0000000000000000000000000000000000000054": { "balance": "0" }, + "0000000000000000000000000000000000000055": { "balance": "0" }, + "0000000000000000000000000000000000000056": { "balance": "0" }, + "0000000000000000000000000000000000000057": { "balance": "0" }, + "0000000000000000000000000000000000000058": { "balance": "0" }, + "0000000000000000000000000000000000000059": { "balance": "0" }, + "000000000000000000000000000000000000005a": { "balance": "0" }, + "000000000000000000000000000000000000005b": { "balance": "0" }, + "000000000000000000000000000000000000005c": { "balance": "0" }, + "000000000000000000000000000000000000005d": { "balance": "0" }, + "000000000000000000000000000000000000005e": { "balance": "0" }, + "000000000000000000000000000000000000005f": { "balance": "0" }, + "0000000000000000000000000000000000000060": { "balance": "0" }, + "0000000000000000000000000000000000000061": { "balance": "0" }, + "0000000000000000000000000000000000000062": { "balance": "0" }, + "0000000000000000000000000000000000000063": { "balance": "0" }, + "0000000000000000000000000000000000000064": { "balance": "0" }, + "0000000000000000000000000000000000000065": { "balance": "0" }, + "0000000000000000000000000000000000000066": { "balance": "0" }, + "0000000000000000000000000000000000000067": { "balance": "0" }, + "0000000000000000000000000000000000000068": { "balance": "0" }, + "0000000000000000000000000000000000000069": { "balance": "0" }, + "000000000000000000000000000000000000006a": { "balance": "0" }, + "000000000000000000000000000000000000006b": { "balance": "0" }, + "000000000000000000000000000000000000006c": { "balance": "0" }, + "000000000000000000000000000000000000006d": { "balance": "0" }, + "000000000000000000000000000000000000006e": { "balance": "0" }, + "000000000000000000000000000000000000006f": { "balance": "0" }, + "0000000000000000000000000000000000000070": { "balance": "0" }, + "0000000000000000000000000000000000000071": { "balance": "0" }, + "0000000000000000000000000000000000000072": { "balance": "0" }, + "0000000000000000000000000000000000000073": { "balance": "0" }, + "0000000000000000000000000000000000000074": { "balance": "0" }, + "0000000000000000000000000000000000000075": { "balance": "0" }, + "0000000000000000000000000000000000000076": { "balance": "0" }, + "0000000000000000000000000000000000000077": { "balance": "0" }, + "0000000000000000000000000000000000000078": { "balance": "0" }, + "0000000000000000000000000000000000000079": { "balance": "0" }, + "000000000000000000000000000000000000007a": { "balance": "0" }, + "000000000000000000000000000000000000007b": { "balance": "0" }, + "000000000000000000000000000000000000007c": { "balance": "0" }, + "000000000000000000000000000000000000007d": { "balance": "0" }, + "000000000000000000000000000000000000007e": { "balance": "0" }, + "000000000000000000000000000000000000007f": { "balance": "0" }, + "0000000000000000000000000000000000000080": { "balance": "0" }, + "0000000000000000000000000000000000000081": { "balance": "0" }, + "0000000000000000000000000000000000000082": { "balance": "0" }, + "0000000000000000000000000000000000000083": { "balance": "0" }, + "0000000000000000000000000000000000000084": { "balance": "0" }, + "0000000000000000000000000000000000000085": { "balance": "0" }, + "0000000000000000000000000000000000000086": { "balance": "0" }, + "0000000000000000000000000000000000000087": { "balance": "0" }, + "0000000000000000000000000000000000000088": { "balance": "0" }, + "0000000000000000000000000000000000000089": { "balance": "0" }, + "000000000000000000000000000000000000008a": { "balance": "0" }, + "000000000000000000000000000000000000008b": { "balance": "0" }, + "000000000000000000000000000000000000008c": { "balance": "0" }, + "000000000000000000000000000000000000008d": { "balance": "0" }, + "000000000000000000000000000000000000008e": { "balance": "0" }, + "000000000000000000000000000000000000008f": { "balance": "0" }, + "0000000000000000000000000000000000000090": { "balance": "0" }, + "0000000000000000000000000000000000000091": { "balance": "0" }, + "0000000000000000000000000000000000000092": { "balance": "0" }, + "0000000000000000000000000000000000000093": { "balance": "0" }, + "0000000000000000000000000000000000000094": { "balance": "0" }, + "0000000000000000000000000000000000000095": { "balance": "0" }, + "0000000000000000000000000000000000000096": { "balance": "0" }, + "0000000000000000000000000000000000000097": { "balance": "0" }, + "0000000000000000000000000000000000000098": { "balance": "0" }, + "0000000000000000000000000000000000000099": { "balance": "0" }, + "000000000000000000000000000000000000009a": { "balance": "0" }, + "000000000000000000000000000000000000009b": { "balance": "0" }, + "000000000000000000000000000000000000009c": { "balance": "0" }, + "000000000000000000000000000000000000009d": { "balance": "0" }, + "000000000000000000000000000000000000009e": { "balance": "0" }, + "000000000000000000000000000000000000009f": { "balance": "0" }, + "00000000000000000000000000000000000000a0": { "balance": "0" }, + "00000000000000000000000000000000000000a1": { "balance": "0" }, + "00000000000000000000000000000000000000a2": { "balance": "0" }, + "00000000000000000000000000000000000000a3": { "balance": "0" }, + "00000000000000000000000000000000000000a4": { "balance": "0" }, + "00000000000000000000000000000000000000a5": { "balance": "0" }, + "00000000000000000000000000000000000000a6": { "balance": "0" }, + "00000000000000000000000000000000000000a7": { "balance": "0" }, + "00000000000000000000000000000000000000a8": { "balance": "0" }, + "00000000000000000000000000000000000000a9": { "balance": "0" }, + "00000000000000000000000000000000000000aa": { "balance": "0" }, + "00000000000000000000000000000000000000ab": { "balance": "0" }, + "00000000000000000000000000000000000000ac": { "balance": "0" }, + "00000000000000000000000000000000000000ad": { "balance": "0" }, + "00000000000000000000000000000000000000ae": { "balance": "0" }, + "00000000000000000000000000000000000000af": { "balance": "0" }, + "00000000000000000000000000000000000000b0": { "balance": "0" }, + "00000000000000000000000000000000000000b1": { "balance": "0" }, + "00000000000000000000000000000000000000b2": { "balance": "0" }, + "00000000000000000000000000000000000000b3": { "balance": "0" }, + "00000000000000000000000000000000000000b4": { "balance": "0" }, + "00000000000000000000000000000000000000b5": { "balance": "0" }, + "00000000000000000000000000000000000000b6": { "balance": "0" }, + "00000000000000000000000000000000000000b7": { "balance": "0" }, + "00000000000000000000000000000000000000b8": { "balance": "0" }, + "00000000000000000000000000000000000000b9": { "balance": "0" }, + "00000000000000000000000000000000000000ba": { "balance": "0" }, + "00000000000000000000000000000000000000bb": { "balance": "0" }, + "00000000000000000000000000000000000000bc": { "balance": "0" }, + "00000000000000000000000000000000000000bd": { "balance": "0" }, + "00000000000000000000000000000000000000be": { "balance": "0" }, + "00000000000000000000000000000000000000bf": { "balance": "0" }, + "00000000000000000000000000000000000000c0": { "balance": "0" }, + "00000000000000000000000000000000000000c1": { "balance": "0" }, + "00000000000000000000000000000000000000c2": { "balance": "0" }, + "00000000000000000000000000000000000000c3": { "balance": "0" }, + "00000000000000000000000000000000000000c4": { "balance": "0" }, + "00000000000000000000000000000000000000c5": { "balance": "0" }, + "00000000000000000000000000000000000000c6": { "balance": "0" }, + "00000000000000000000000000000000000000c7": { "balance": "0" }, + "00000000000000000000000000000000000000c8": { "balance": "0" }, + "00000000000000000000000000000000000000c9": { "balance": "0" }, + "00000000000000000000000000000000000000ca": { "balance": "0" }, + "00000000000000000000000000000000000000cb": { "balance": "0" }, + "00000000000000000000000000000000000000cc": { "balance": "0" }, + "00000000000000000000000000000000000000cd": { "balance": "0" }, + "00000000000000000000000000000000000000ce": { "balance": "0" }, + "00000000000000000000000000000000000000cf": { "balance": "0" }, + "00000000000000000000000000000000000000d0": { "balance": "0" }, + "00000000000000000000000000000000000000d1": { "balance": "0" }, + "00000000000000000000000000000000000000d2": { "balance": "0" }, + "00000000000000000000000000000000000000d3": { "balance": "0" }, + "00000000000000000000000000000000000000d4": { "balance": "0" }, + "00000000000000000000000000000000000000d5": { "balance": "0" }, + "00000000000000000000000000000000000000d6": { "balance": "0" }, + "00000000000000000000000000000000000000d7": { "balance": "0" }, + "00000000000000000000000000000000000000d8": { "balance": "0" }, + "00000000000000000000000000000000000000d9": { "balance": "0" }, "00000000000000000000000000000000000000da": { "balance": "0" }, - "00000000000000000000000000000000000000db": { "balance": "0" }, - "00000000000000000000000000000000000000dc": { "balance": "0" }, - "00000000000000000000000000000000000000dd": { "balance": "0" }, - "00000000000000000000000000000000000000de": { "balance": "0" }, - "00000000000000000000000000000000000000df": { "balance": "0" }, - "00000000000000000000000000000000000000e0": { "balance": "0" }, - "00000000000000000000000000000000000000e1": { "balance": "0" }, - "00000000000000000000000000000000000000e2": { "balance": "0" }, - "00000000000000000000000000000000000000e3": { "balance": "0" }, - "00000000000000000000000000000000000000e4": { "balance": "0" }, - "00000000000000000000000000000000000000e5": { "balance": "0" }, - "00000000000000000000000000000000000000e6": { "balance": "0" }, - "00000000000000000000000000000000000000e7": { "balance": "0" }, - "00000000000000000000000000000000000000e8": { "balance": "0" }, - "00000000000000000000000000000000000000e9": { "balance": "0" }, - "00000000000000000000000000000000000000ea": { "balance": "0" }, - "00000000000000000000000000000000000000eb": { "balance": "0" }, - "00000000000000000000000000000000000000ec": { "balance": "0" }, - "00000000000000000000000000000000000000ed": { "balance": "0" }, - "00000000000000000000000000000000000000ee": { "balance": "0" }, - "00000000000000000000000000000000000000ef": { "balance": "0" }, - "00000000000000000000000000000000000000f0": { "balance": "0" }, - "00000000000000000000000000000000000000f1": { "balance": "0" }, - "00000000000000000000000000000000000000f2": { "balance": "0" }, - "00000000000000000000000000000000000000f3": { "balance": "0" }, - "00000000000000000000000000000000000000f4": { "balance": "0" }, - "00000000000000000000000000000000000000f5": { "balance": "0" }, - "00000000000000000000000000000000000000f6": { "balance": "0" }, - "00000000000000000000000000000000000000f7": { "balance": "0" }, - "00000000000000000000000000000000000000f8": { "balance": "0" }, - "00000000000000000000000000000000000000f9": { "balance": "0" }, - "00000000000000000000000000000000000000fa": { "balance": "0" }, - "00000000000000000000000000000000000000fb": { "balance": "0" }, - "00000000000000000000000000000000000000fc": { "balance": "0" }, - "00000000000000000000000000000000000000fd": { "balance": "0" }, - "00000000000000000000000000000000000000fe": { "balance": "0" }, - "00000000000000000000000000000000000000ff": { "balance": "0" }, + "00000000000000000000000000000000000000db": { "balance": "0" }, + "00000000000000000000000000000000000000dc": { "balance": "0" }, + "00000000000000000000000000000000000000dd": { "balance": "0" }, + "00000000000000000000000000000000000000de": { "balance": "0" }, + "00000000000000000000000000000000000000df": { "balance": "0" }, + "00000000000000000000000000000000000000e0": { "balance": "0" }, + "00000000000000000000000000000000000000e1": { "balance": "0" }, + "00000000000000000000000000000000000000e2": { "balance": "0" }, + "00000000000000000000000000000000000000e3": { "balance": "0" }, + "00000000000000000000000000000000000000e4": { "balance": "0" }, + "00000000000000000000000000000000000000e5": { "balance": "0" }, + "00000000000000000000000000000000000000e6": { "balance": "0" }, + "00000000000000000000000000000000000000e7": { "balance": "0" }, + "00000000000000000000000000000000000000e8": { "balance": "0" }, + "00000000000000000000000000000000000000e9": { "balance": "0" }, + "00000000000000000000000000000000000000ea": { "balance": "0" }, + "00000000000000000000000000000000000000eb": { "balance": "0" }, + "00000000000000000000000000000000000000ec": { "balance": "0" }, + "00000000000000000000000000000000000000ed": { "balance": "0" }, + "00000000000000000000000000000000000000ee": { "balance": "0" }, + "00000000000000000000000000000000000000ef": { "balance": "0" }, + "00000000000000000000000000000000000000f0": { "balance": "0" }, + "00000000000000000000000000000000000000f1": { "balance": "0" }, + "00000000000000000000000000000000000000f2": { "balance": "0" }, + "00000000000000000000000000000000000000f3": { "balance": "0" }, + "00000000000000000000000000000000000000f4": { "balance": "0" }, + "00000000000000000000000000000000000000f5": { "balance": "0" }, + "00000000000000000000000000000000000000f6": { "balance": "0" }, + "00000000000000000000000000000000000000f7": { "balance": "0" }, + "00000000000000000000000000000000000000f8": { "balance": "0" }, + "00000000000000000000000000000000000000f9": { "balance": "0" }, + "00000000000000000000000000000000000000fa": { "balance": "0" }, + "00000000000000000000000000000000000000fb": { "balance": "0" }, + "00000000000000000000000000000000000000fc": { "balance": "0" }, + "00000000000000000000000000000000000000fd": { "balance": "0" }, + "00000000000000000000000000000000000000fe": { "balance": "0" }, + "00000000000000000000000000000000000000ff": { "balance": "0" }, "874b54a8bd152966d63f706bae1ffeb0411921e5": { "balance": "1000000000000000000000000000000" } } } diff --git a/ethcore/res/ethereum/tests b/ethcore/res/ethereum/tests index 9028c4801..d509c7593 160000 --- a/ethcore/res/ethereum/tests +++ b/ethcore/res/ethereum/tests @@ -1 +1 @@ -Subproject commit 9028c4801fd39fbb71a9796979182549a24e81c8 +Subproject commit d509c75936ec6cbba683ee1916aa0bca436bc376 diff --git a/ethcore/res/instant_seal.json b/ethcore/res/instant_seal.json index 2d5b38659..a6b24faf9 100644 --- a/ethcore/res/instant_seal.json +++ b/ethcore/res/instant_seal.json @@ -11,9 +11,9 @@ }, "genesis": { "seal": { - "ethereum": { - "nonce": "0x00006d6f7264656e", - "mixHash": "0x00000000000000000000000000000000000000647572616c65787365646c6578" + "generic": { + "fields": 0, + "rlp": "0x0" } }, "difficulty": "0x20000", diff --git a/ethcore/src/account_db.rs b/ethcore/src/account_db.rs index 0761b7fba..63524a442 100644 --- a/ethcore/src/account_db.rs +++ b/ethcore/src/account_db.rs @@ -121,10 +121,6 @@ impl<'db> HashDB for AccountDB<'db>{ fn remove(&mut self, _key: &H256) { unimplemented!() } - - fn get_aux(&self, hash: &[u8]) -> Option { - self.db.get_aux(hash) - } } /// DB backend wrapper for Account trie @@ -197,18 +193,6 @@ impl<'db> HashDB for AccountDBMut<'db>{ let key = combine_key(&self.address_hash, key); self.db.remove(&key) } - - fn insert_aux(&mut self, hash: Vec, value: Vec) { - self.db.insert_aux(hash, value); - } - - fn get_aux(&self, hash: &[u8]) -> Option { - self.db.get_aux(hash) - } - - fn remove_aux(&mut self, hash: &[u8]) { - self.db.remove_aux(hash); - } } struct Wrapping<'db>(&'db HashDB); diff --git a/ethcore/src/account_provider.rs b/ethcore/src/account_provider.rs index e906aefe9..917ae8b8b 100644 --- a/ethcore/src/account_provider.rs +++ b/ethcore/src/account_provider.rs @@ -276,14 +276,20 @@ impl AccountProvider { } /// Returns `true` if the password for `account` is `password`. `false` if not. - pub fn test_password(&self, account: &Address, password: String) -> Result { - match self.sstore.sign(account, &password, &Default::default()) { + pub fn test_password(&self, account: &Address, password: &str) -> Result { + match self.sstore.sign(account, password, &Default::default()) { Ok(_) => Ok(true), Err(SSError::InvalidPassword) => Ok(false), Err(e) => Err(Error::SStore(e)), } } + /// Permanently removes an account. + pub fn kill_account(&self, account: &Address, password: &str) -> Result<(), Error> { + try!(self.sstore.remove_account(account, &password)); + Ok(()) + } + /// Changes the password of `account` from `password` to `new_password`. Fails if incorrect `password` given. pub fn change_password(&self, account: &Address, password: String, new_password: String) -> Result<(), Error> { self.sstore.change_password(account, &password, &new_password).map_err(Error::SStore) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 54c2a7a02..bcbceb9aa 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -594,9 +594,9 @@ mod tests { use factory::Factories; use state_db::StateDB; use views::BlockView; - use util::Address; + use util::{Address, TrieFactory}; use util::hash::FixedHash; - + use util::trie::TrieSpec; use std::sync::Arc; /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header @@ -637,7 +637,7 @@ mod tests { let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); let mut db = db_result.take(); - spec.ensure_db_good(&mut db).unwrap(); + spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(&*spec.engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = b.close_and_lock(); @@ -653,7 +653,7 @@ mod tests { let mut db_result = get_temp_state_db(); let mut db = db_result.take(); - spec.ensure_db_good(&mut db).unwrap(); + spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap() .close_and_lock().seal(engine, vec![]).unwrap(); @@ -662,7 +662,7 @@ mod tests { let mut db_result = get_temp_state_db(); let mut db = db_result.take(); - spec.ensure_db_good(&mut db).unwrap(); + spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, Default::default()).unwrap(); assert_eq!(e.rlp_bytes(), orig_bytes); @@ -681,7 +681,7 @@ mod tests { let mut db_result = get_temp_state_db(); let mut db = db_result.take(); - spec.ensure_db_good(&mut db).unwrap(); + spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let mut open_block = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let mut uncle1_header = Header::new(); @@ -697,7 +697,7 @@ mod tests { let mut db_result = get_temp_state_db(); let mut db = db_result.take(); - spec.ensure_db_good(&mut db).unwrap(); + spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, Default::default()).unwrap(); let bytes = e.rlp_bytes(); diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 5910d0309..68fb40483 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -140,7 +140,7 @@ pub trait BlockProvider { fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockNumber, to_block: BlockNumber) -> Vec; /// Returns logs matching given filter. - fn logs(&self, mut blocks: Vec, matches: F, limit: Option) -> Vec + fn logs(&self, blocks: Vec, matches: F, limit: Option) -> Vec where F: Fn(&LogEntry) -> bool, Self: Sized; } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 2dd4b7843..9204d3f93 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -22,7 +22,7 @@ use std::time::{Instant}; use time::precise_time_ns; // util -use util::{Bytes, PerfTimer, Itertools, Mutex, RwLock}; +use util::{Bytes, PerfTimer, Itertools, Mutex, RwLock, Hashable}; use util::{journaldb, TrieFactory, Trie}; use util::trie::TrieSpec; use util::{U256, H256, Address, H2048, Uint, FixedHash}; @@ -173,9 +173,10 @@ impl Client { false => TrieSpec::Secure, }; + let trie_factory = TrieFactory::new(trie_spec); let journal_db = journaldb::new(db.clone(), config.pruning, ::db::COL_STATE); let mut state_db = StateDB::new(journal_db, config.state_cache_size); - if state_db.journal_db().is_empty() && try!(spec.ensure_db_good(&mut state_db)) { + if state_db.journal_db().is_empty() && try!(spec.ensure_db_good(&mut state_db, &trie_factory)) { let mut batch = DBTransaction::new(&db); try!(state_db.journal_under(&mut batch, 0, &spec.genesis_header().hash())); try!(db.write(batch).map_err(ClientError::Database)); @@ -217,7 +218,7 @@ impl Client { let factories = Factories { vm: EvmFactory::new(config.vm_type.clone(), config.jump_table_size), - trie: TrieFactory::new(trie_spec), + trie: trie_factory, accountdb: Default::default(), }; @@ -870,8 +871,8 @@ impl BlockChainClient for Client { } fn keep_alive(&self) { - let should_wake = match &*self.mode.lock() { - &Mode::Dark(..) | &Mode::Passive(..) => true, + let should_wake = match *self.mode.lock() { + Mode::Dark(..) | Mode::Passive(..) => true, _ => false, }; if should_wake { @@ -953,6 +954,10 @@ impl BlockChainClient for Client { self.state_at(id).map(|s| s.nonce(address)) } + fn storage_root(&self, address: &Address, id: BlockID) -> Option { + self.state_at(id).and_then(|s| s.storage_root(address)) + } + fn block_hash(&self, id: BlockID) -> Option { let chain = self.chain.read(); Self::block_hash(&chain, id) @@ -970,7 +975,7 @@ impl BlockChainClient for Client { self.state_at(id).map(|s| s.storage_at(address, position)) } - fn list_accounts(&self, id: BlockID) -> Option> { + fn list_accounts(&self, id: BlockID, after: Option<&Address>, count: u64) -> Option> { if !self.factories.trie.is_fat() { trace!(target: "fatdb", "list_accounts: Not a fat DB"); return None; @@ -990,18 +995,68 @@ impl BlockChainClient for Client { } }; - let iter = match trie.iter() { + let mut iter = match trie.iter() { Ok(iter) => iter, _ => return None, }; + if let Some(after) = after { + if let Err(e) = iter.seek(after) { + trace!(target: "fatdb", "list_accounts: Couldn't seek the DB: {:?}", e); + } + } + let accounts = iter.filter_map(|item| { item.ok().map(|(addr, _)| Address::from_slice(&addr)) - }).collect(); + }).take(count as usize).collect(); Some(accounts) } + fn list_storage(&self, id: BlockID, account: &Address, after: Option<&H256>, count: u64) -> Option> { + if !self.factories.trie.is_fat() { + trace!(target: "fatdb", "list_stroage: Not a fat DB"); + return None; + } + + let state = match self.state_at(id) { + Some(state) => state, + _ => return None, + }; + + let root = match state.storage_root(account) { + Some(root) => root, + _ => return None, + }; + + let (_, db) = state.drop(); + let account_db = self.factories.accountdb.readonly(db.as_hashdb(), account.sha3()); + let trie = match self.factories.trie.readonly(account_db.as_hashdb(), &root) { + Ok(trie) => trie, + _ => { + trace!(target: "fatdb", "list_storage: Couldn't open the DB"); + return None; + } + }; + + let mut iter = match trie.iter() { + Ok(iter) => iter, + _ => return None, + }; + + if let Some(after) = after { + if let Err(e) = iter.seek(after) { + trace!(target: "fatdb", "list_accounts: Couldn't seek the DB: {:?}", e); + } + } + + let keys = iter.filter_map(|item| { + item.ok().map(|(key, _)| H256::from_slice(&key)) + }).take(count as usize).collect(); + + Some(keys) + } + fn transaction(&self, id: TransactionID) -> Option { self.transaction_address(id).and_then(|address| self.chain.read().transaction(&address)) } diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index d2a932e07..b5535fce2 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -334,7 +334,7 @@ impl MiningBlockChainClient for TestBlockChainClient { let genesis_header = self.spec.genesis_header(); let mut db_result = get_temp_state_db(); let mut db = db_result.take(); - self.spec.ensure_db_good(&mut db).unwrap(); + self.spec.ensure_db_good(&mut db, &TrieFactory::default()).unwrap(); let last_hashes = vec![genesis_header.hash()]; let mut open_block = OpenBlock::new( @@ -386,6 +386,10 @@ impl BlockChainClient for TestBlockChainClient { } } + fn storage_root(&self, _address: &Address, _id: BlockID) -> Option { + None + } + fn latest_nonce(&self, address: &Address) -> U256 { self.nonce(address, BlockID::Latest).unwrap() } @@ -417,10 +421,13 @@ impl BlockChainClient for TestBlockChainClient { } } - fn list_accounts(&self, _id: BlockID) -> Option> { + fn list_accounts(&self, _id: BlockID, _after: Option<&Address>, _count: u64) -> Option> { None } + fn list_storage(&self, _id: BlockID, _account: &Address, _after: Option<&H256>, _count: u64) -> Option> { + None + } fn transaction(&self, _id: TransactionID) -> Option { None // Simple default. } diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index 2cbf52f6c..d2cafa592 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -69,6 +69,10 @@ pub trait BlockChainClient : Sync + Send { /// May not fail on BlockID::Latest. fn nonce(&self, address: &Address, id: BlockID) -> Option; + /// Attempt to get address storage root at given block. + /// May not fail on BlockID::Latest. + fn storage_root(&self, address: &Address, id: BlockID) -> Option; + /// Get address nonce at the latest block's state. fn latest_nonce(&self, address: &Address) -> U256 { self.nonce(address, BlockID::Latest) @@ -115,7 +119,12 @@ pub trait BlockChainClient : Sync + Send { } /// Get a list of all accounts in the block `id`, if fat DB is in operation, otherwise `None`. - fn list_accounts(&self, id: BlockID) -> Option>; + /// If `after` is set the list starts with the following item. + fn list_accounts(&self, id: BlockID, after: Option<&Address>, count: u64) -> Option>; + + /// Get a list of all storage keys in the block `id`, if fat DB is in operation, otherwise `None`. + /// If `after` is set the list starts with the following item. + fn list_storage(&self, id: BlockID, account: &Address, after: Option<&H256>, count: u64) -> Option>; /// Get transaction with given hash. fn transaction(&self, id: TransactionID) -> Option; diff --git a/ethcore/src/engines/authority_round.rs b/ethcore/src/engines/authority_round.rs index 9bed99e8b..6c1d0a409 100644 --- a/ethcore/src/engines/authority_round.rs +++ b/ethcore/src/engines/authority_round.rs @@ -124,7 +124,7 @@ impl AuthorityRound { } fn step_proposer(&self, step: usize) -> &Address { - let ref p = self.our_params; + let p = &self.our_params; p.authorities.get(step % p.authority_n).expect("There are authority_n authorities; taking number modulo authority_n gives number in authority_n range; qed") } @@ -211,7 +211,7 @@ impl Engine for AuthorityRound { fn on_close_block(&self, _block: &mut ExecutedBlock) {} fn is_sealer(&self, author: &Address) -> Option { - let ref p = self.our_params; + let p = &self.our_params; Some(p.authorities.contains(author)) } @@ -254,8 +254,8 @@ impl Engine for AuthorityRound { /// Check if the signature belongs to the correct proposer. fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> { - let header_step = try!(header_step(header)); - // Give one step slack if step is lagging, double vote is still not possible. + let header_step = try!(header_step(header)); + // Give one step slack if step is lagging, double vote is still not possible. if header_step <= self.step() + 1 { let proposer_signature = try!(header_signature(header)); let ok_sig = try!(verify_address(self.step_proposer(header_step), &proposer_signature, &header.bare_hash())); @@ -279,7 +279,7 @@ impl Engine for AuthorityRound { let step = try!(header_step(header)); // Check if parent is from a previous step. - if step == try!(header_step(parent)) { + if step == try!(header_step(parent)) { trace!(target: "poa", "Multiple blocks proposed for step {}.", step); try!(Err(BlockError::DoubleVote(header.author().clone()))); } @@ -315,6 +315,7 @@ impl Engine for AuthorityRound { #[cfg(test)] mod tests { use util::*; + use util::trie::TrieSpec; use env_info::EnvInfo; use header::Header; use error::{Error, BlockError}; @@ -384,9 +385,9 @@ mod tests { let engine = &*spec.engine; let genesis_header = spec.genesis_header(); let mut db1 = get_temp_state_db().take(); - spec.ensure_db_good(&mut db1).unwrap(); + spec.ensure_db_good(&mut db1, &TrieFactory::new(TrieSpec::Secure)).unwrap(); let mut db2 = get_temp_state_db().take(); - spec.ensure_db_good(&mut db2).unwrap(); + spec.ensure_db_good(&mut db2, &TrieFactory::new(TrieSpec::Secure)).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![]).unwrap(); let b1 = b1.close_and_lock(); @@ -417,13 +418,13 @@ mod tests { let engine = Spec::new_test_round().engine; let signature = tap.sign(addr, Some("0".into()), header.bare_hash()).unwrap(); - let mut step = UNIX_EPOCH.elapsed().unwrap().as_secs(); + let time = UNIX_EPOCH.elapsed().unwrap().as_secs(); + // Two authorities. + let mut step = time - time % 2; header.set_seal(vec![encode(&step).to_vec(), encode(&(&*signature as &[u8])).to_vec()]); - let first_ok = engine.verify_block_seal(&header).is_ok(); + assert!(engine.verify_block_seal(&header).is_err()); step = step + 1; header.set_seal(vec![encode(&step).to_vec(), encode(&(&*signature as &[u8])).to_vec()]); - let second_ok = engine.verify_block_seal(&header).is_ok(); - - assert!(first_ok ^ second_ok); + assert!(engine.verify_block_seal(&header).is_ok()); } } diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 23a97967c..fb2f9bde6 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -184,6 +184,7 @@ impl Engine for BasicAuthority { #[cfg(test)] mod tests { use util::*; + use util::trie::TrieSpec; use block::*; use env_info::EnvInfo; use error::{BlockError, Error}; @@ -256,7 +257,7 @@ mod tests { let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); let mut db = db_result.take(); - spec.ensure_db_good(&mut db).unwrap(); + spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = b.close_and_lock(); diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index 3dc78d1a2..f50f7344b 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -68,6 +68,7 @@ impl Engine for InstantSeal { #[cfg(test)] mod tests { use util::*; + use util::trie::TrieSpec; use tests::helpers::*; use account_provider::AccountProvider; use spec::Spec; @@ -84,7 +85,7 @@ mod tests { let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); let mut db = db_result.take(); - spec.ensure_db_good(&mut db).unwrap(); + spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = b.close_and_lock(); diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index de2a85942..38a1df525 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -422,6 +422,7 @@ impl Header { #[cfg(test)] mod tests { use util::*; + use util::trie::TrieSpec; use block::*; use tests::helpers::*; use env_info::EnvInfo; @@ -438,7 +439,7 @@ mod tests { let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); let mut db = db_result.take(); - spec.ensure_db_good(&mut db).unwrap(); + spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = b.close(); @@ -452,7 +453,7 @@ mod tests { let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); let mut db = db_result.take(); - spec.ensure_db_good(&mut db).unwrap(); + spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let mut b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let mut uncle = Header::new(); diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index e236924ad..3916e5ccc 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -72,6 +72,7 @@ pub fn new_morden() -> Spec { load(include_bytes!("../../res/ethereum/morden.jso #[cfg(test)] mod tests { use util::*; + use util::trie::TrieSpec; use state::*; use super::*; use tests::helpers::*; @@ -84,7 +85,7 @@ mod tests { let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); let mut db = db_result.take(); - spec.ensure_db_good(&mut db).unwrap(); + spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); let s = State::from_existing(db, genesis_header.state_root().clone(), engine.account_start_nonce(), Default::default()).unwrap(); assert_eq!(s.balance(&"0000000000000000000000000000000000000001".into()), 1u64.into()); assert_eq!(s.balance(&"0000000000000000000000000000000000000002".into()), 1u64.into()); diff --git a/ethcore/src/evm/interpreter/gasometer.rs b/ethcore/src/evm/interpreter/gasometer.rs index beaaadac5..886120880 100644 --- a/ethcore/src/evm/interpreter/gasometer.rs +++ b/ethcore/src/evm/interpreter/gasometer.rs @@ -197,19 +197,17 @@ impl Gasometer { let address = u256_to_address(stack.peek(1)); let is_value_transfer = !stack.peek(2).is_zero(); - if instruction == instructions::CALL { - if ( - !schedule.no_empty && !ext.exists(&address) - ) || ( - schedule.no_empty && is_value_transfer && !ext.exists_and_not_null(&address) - ) { - gas = overflowing!(gas.overflow_add(schedule.call_new_account_gas.into())); - } - }; + if instruction == instructions::CALL && ( + (!schedule.no_empty && !ext.exists(&address)) + || + (schedule.no_empty && is_value_transfer && !ext.exists_and_not_null(&address)) + ) { + gas = overflowing!(gas.overflow_add(schedule.call_new_account_gas.into())); + } if is_value_transfer { gas = overflowing!(gas.overflow_add(schedule.call_value_transfer_gas.into())); - }; + } let requested = *stack.peek(0); @@ -347,7 +345,7 @@ fn test_mem_gas_cost() { let result = gasometer.mem_gas_cost(&schedule, current_mem_size, &mem_size); // then - if let Ok(_) = result { + if result.is_ok() { assert!(false, "Should fail with OutOfGas"); } } diff --git a/ethcore/src/evm/tests.rs b/ethcore/src/evm/tests.rs index 7e69c0771..6cfc9a43e 100644 --- a/ethcore/src/evm/tests.rs +++ b/ethcore/src/evm/tests.rs @@ -95,7 +95,7 @@ impl Ext for FakeExt { } fn exists_and_not_null(&self, address: &Address) -> bool { - self.balances.get(address).map_or(false, |b| !b.is_zero()) + self.balances.get(address).map_or(false, |b| !b.is_zero()) } fn origin_balance(&self) -> U256 { @@ -103,7 +103,7 @@ impl Ext for FakeExt { } fn balance(&self, address: &Address) -> U256 { - *self.balances.get(address).unwrap() + self.balances[address] } fn blockhash(&self, number: &U256) -> H256 { diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 5da105e2f..1dfd987c1 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -445,7 +445,7 @@ impl<'a> Executive<'a> { trace!("exec::finalize: Refunding refund_value={}, sender={}\n", refund_value, sender); // Below: NoEmpty is safe since the sender must already be non-null to have sent this transaction - self.state.add_balance(&sender, &refund_value, CleanupMode::NoEmpty); + self.state.add_balance(&sender, &refund_value, CleanupMode::NoEmpty); trace!("exec::finalize: Compensating author: fees_value={}, author={}\n", fees_value, &self.info.author); self.state.add_balance(&self.info.author, &fees_value, substate.to_cleanup_mode(&schedule)); @@ -514,9 +514,11 @@ impl<'a> Executive<'a> { #[cfg(test)] #[allow(dead_code)] mod tests { + use std::sync::Arc; use ethkey::{Generator, Random}; use super::*; - use util::*; + use util::{H256, U256, U512, Address, Uint, FixedHash, FromHex, FromStr}; + use util::bytes::BytesRef; use action_params::{ActionParams, ActionValue}; use env_info::EnvInfo; use evm::{Factory, VMType}; diff --git a/ethcore/src/json_tests/transaction.rs b/ethcore/src/json_tests/transaction.rs index 438852124..12e82bca2 100644 --- a/ethcore/src/json_tests/transaction.rs +++ b/ethcore/src/json_tests/transaction.rs @@ -34,7 +34,7 @@ fn do_json_test(json_data: &[u8]) -> Vec { Some(x) if x < 1_150_000 => &old_schedule, Some(_) => &new_schedule }; - let allow_network_id_of_one = number.map_or(false, |n| n >= 3_500_000); + let allow_network_id_of_one = number.map_or(false, |n| n >= 2_675_000); let rlp: Vec = test.rlp.into(); let res = UntrustedRlp::new(&rlp) diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 7ad18ebfc..a543e608d 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -151,7 +151,7 @@ impl GasPriceCalibrator { if Instant::now() >= self.next_calibration { let usd_per_tx = self.options.usd_per_tx; trace!(target: "miner", "Getting price info"); - if let Ok(_) = PriceInfo::get(move |price: PriceInfo| { + let price_info = PriceInfo::get(move |price: PriceInfo| { trace!(target: "miner", "Price info arrived: {:?}", price); let usd_per_eth = price.ethusd; let wei_per_usd: f32 = 1.0e18 / usd_per_eth; @@ -159,7 +159,9 @@ impl GasPriceCalibrator { let wei_per_gas: f32 = wei_per_usd * usd_per_tx / gas_per_tx; info!(target: "miner", "Updated conversion rate to Ξ1 = {} ({} wei/gas)", Colour::White.bold().paint(format!("US${}", usd_per_eth)), Colour::Yellow.bold().paint(format!("{}", wei_per_gas))); set_price(U256::from(wei_per_gas as u64)); - }) { + }); + + if price_info.is_ok() { self.next_calibration = Instant::now() + self.options.recalibration_period; } else { warn!(target: "miner", "Unable to update Ether price."); @@ -580,29 +582,29 @@ impl Miner { let gas_required = |tx: &SignedTransaction| tx.gas_required(&schedule).into(); let best_block_header: Header = ::rlp::decode(&chain.best_block_header()); transactions.into_iter() - .filter(|tx| match self.engine.verify_transaction_basic(tx, &best_block_header) { - Ok(()) => true, + .map(|tx| { + match self.engine.verify_transaction_basic(&tx, &best_block_header) { Err(e) => { debug!(target: "miner", "Rejected tx {:?} with invalid signature: {:?}", tx.hash(), e); - false - } - } - ) - .map(|tx| { - let origin = accounts.as_ref().and_then(|accounts| { - tx.sender().ok().and_then(|sender| match accounts.contains(&sender) { - true => Some(TransactionOrigin::Local), - false => None, - }) - }).unwrap_or(default_origin); - - match origin { - TransactionOrigin::Local | TransactionOrigin::RetractedBlock => { - transaction_queue.add(tx, origin, &fetch_account, &gas_required) + Err(e) + }, + Ok(()) => { + let origin = accounts.as_ref().and_then(|accounts| { + tx.sender().ok().and_then(|sender| match accounts.contains(&sender) { + true => Some(TransactionOrigin::Local), + false => None, + }) + }).unwrap_or(default_origin); + + match origin { + TransactionOrigin::Local | TransactionOrigin::RetractedBlock => { + transaction_queue.add(tx, origin, &fetch_account, &gas_required) + }, + TransactionOrigin::External => { + transaction_queue.add_with_banlist(tx, &fetch_account, &gas_required) + } + } }, - TransactionOrigin::External => { - transaction_queue.add_with_banlist(tx, &fetch_account, &gas_required) - } } }) .collect() @@ -1139,15 +1141,16 @@ impl MinerService for Miner { #[cfg(test)] mod tests { + use std::sync::Arc; use std::time::Duration; use super::super::{MinerService, PrioritizationStrategy}; use super::*; - use util::*; + use block::IsBlock; + use util::{U256, Uint, FromHex}; use ethkey::{Generator, Random}; use client::{BlockChainClient, TestBlockChainClient, EachBlockWith, TransactionImportResult}; use header::BlockNumber; use types::transaction::{Transaction, SignedTransaction, Action}; - use block::*; use spec::Spec; use tests::helpers::{generate_dummy_client}; diff --git a/ethcore/src/miner/transaction_queue.rs b/ethcore/src/miner/transaction_queue.rs index bfbd3fade..cd2d3ba47 100644 --- a/ethcore/src/miner/transaction_queue.rs +++ b/ethcore/src/miner/transaction_queue.rs @@ -990,7 +990,7 @@ impl TransactionQueue { let mut update_last_nonce_to = None; { let by_nonce = self.future.by_address.row_mut(&address); - if let None = by_nonce { + if by_nonce.is_none() { return; } let mut by_nonce = by_nonce.expect("None is tested in early-exit condition above; qed"); @@ -1212,12 +1212,12 @@ mod test { use util::table::*; use util::*; use ethkey::{Random, Generator}; - use transaction::*; use error::{Error, TransactionError}; use super::*; use super::{TransactionSet, TransactionOrder, VerifiedTransaction}; use miner::local_transactions::LocalTransactionsList; use client::TransactionImportResult; + use transaction::{SignedTransaction, Transaction, Action}; fn unwrap_tx_err(err: Result) -> TransactionError { match err.unwrap_err() { diff --git a/ethcore/src/pod_account.rs b/ethcore/src/pod_account.rs index 0882b688c..92a78cebd 100644 --- a/ethcore/src/pod_account.rs +++ b/ethcore/src/pod_account.rs @@ -64,13 +64,13 @@ impl PodAccount { } /// Place additional data into given hash DB. - pub fn insert_additional(&self, db: &mut AccountDBMut) { + pub fn insert_additional(&self, db: &mut AccountDBMut, factory: &TrieFactory) { match self.code { Some(ref c) if !c.is_empty() => { db.insert(c); } _ => {} } let mut r = H256::new(); - let mut t = SecTrieDBMut::new(db, &mut r); + let mut t = factory.create(db, &mut r); for (k, v) in &self.storage { if let Err(e) = t.insert(k, &rlp::encode(&U256::from(&**v))) { warn!("Encountered potential DB corruption: {}", e); diff --git a/ethcore/src/snapshot/mod.rs b/ethcore/src/snapshot/mod.rs index 3f63ac208..408941309 100644 --- a/ethcore/src/snapshot/mod.rs +++ b/ethcore/src/snapshot/mod.rs @@ -552,11 +552,11 @@ const POW_VERIFY_RATE: f32 = 0.02; pub fn verify_old_block(rng: &mut OsRng, header: &Header, engine: &Engine, chain: &BlockChain, body: Option<&[u8]>, always: bool) -> Result<(), ::error::Error> { if always || rng.gen::() <= POW_VERIFY_RATE { match chain.block_header(header.parent_hash()) { - Some(parent) => engine.verify_block_family(&header, &parent, body), - None => engine.verify_block_seal(&header), + Some(parent) => engine.verify_block_family(header, &parent, body), + None => engine.verify_block_seal(header), } } else { - engine.verify_block_basic(&header, body) + engine.verify_block_basic(header, body) } } diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index c8910bbdd..71c15bca2 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -244,13 +244,13 @@ impl Spec { } /// Ensure that the given state DB has the trie nodes in for the genesis state. - pub fn ensure_db_good(&self, db: &mut StateDB) -> Result> { + pub fn ensure_db_good(&self, db: &mut StateDB, factory: &TrieFactory) -> Result> { if !db.as_hashdb().contains(&self.state_root()) { trace!(target: "spec", "ensure_db_good: Fresh database? Cannot find state root {}", self.state_root()); let mut root = H256::new(); { - let mut t = SecTrieDBMut::new(db.as_hashdb_mut(), &mut root); + let mut t = factory.create(db.as_hashdb_mut(), &mut root); for (address, account) in self.genesis_state.get().iter() { try!(t.insert(&**address, &account.rlp())); } @@ -258,7 +258,7 @@ impl Spec { trace!(target: "spec", "ensure_db_good: Populated sec trie; root is {}", root); for (address, account) in self.genesis_state.get().iter() { db.note_non_null_account(address); - account.insert_additional(&mut AccountDBMut::new(db.as_hashdb_mut(), address)); + account.insert_additional(&mut AccountDBMut::new(db.as_hashdb_mut(), address), factory); } assert!(db.as_hashdb().contains(&self.state_root())); Ok(true) diff --git a/ethcore/src/state/account.rs b/ethcore/src/state/account.rs index 4cca0f645..c3d812c46 100644 --- a/ethcore/src/state/account.rs +++ b/ethcore/src/state/account.rs @@ -314,11 +314,10 @@ impl Account { self.code_hash == SHA3_EMPTY } - #[cfg(test)] - /// return the storage root associated with this account or None if it has been altered via the overlay. + /// Return the storage root associated with this account or None if it has been altered via the overlay. pub fn storage_root(&self) -> Option<&H256> { if self.storage_is_clean() {Some(&self.storage_root)} else {None} } - /// return the storage overlay. + /// Return the storage overlay. pub fn storage_changes(&self) -> &HashMap { &self.storage_changes } /// Increment the nonce of the account by one. @@ -466,11 +465,10 @@ impl fmt::Debug for Account { #[cfg(test)] mod tests { - + use rlp::{UntrustedRlp, RlpType, View, Compressible}; use util::*; use super::*; use account_db::*; - use rlp::*; #[test] fn account_compress() { diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index bedc46d9c..b3d63d0ae 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -372,6 +372,12 @@ impl State { |a| a.as_ref().map_or(self.account_start_nonce, |account| *account.nonce())) } + /// Get the storage root of account `a`. + pub fn storage_root(&self, a: &Address) -> Option { + self.ensure_cached(a, RequireCache::None, true, + |a| a.as_ref().and_then(|account| account.storage_root().cloned())) + } + /// Mutate storage of account `address` so that it is `value` for `key`. pub fn storage_at(&self, address: &Address, key: &H256) -> H256 { // Storage key search and update works like this: @@ -448,6 +454,7 @@ impl State { } /// Add `incr` to the balance of account `a`. + #[cfg_attr(feature="dev", allow(single_match))] pub fn add_balance(&mut self, a: &Address, incr: &U256, cleanup_mode: CleanupMode) { trace!(target: "state", "add_balance({}, {}): {}", a, incr, self.balance(a)); let is_value_transfer = !incr.is_zero(); @@ -833,1107 +840,1107 @@ impl Clone for State { #[cfg(test)] mod tests { -use std::sync::Arc; -use std::str::FromStr; -use rustc_serialize::hex::FromHex; -use super::*; -use util::{U256, H256, FixedHash, Address, Hashable}; -use tests::helpers::*; -use devtools::*; -use env_info::EnvInfo; -use spec::*; -use transaction::*; -use util::log::init_log; -use trace::{FlatTrace, TraceError, trace}; -use types::executed::CallType; + use std::sync::Arc; + use std::str::FromStr; + use rustc_serialize::hex::FromHex; + use super::*; + use util::{U256, H256, FixedHash, Address, Hashable}; + use tests::helpers::*; + use devtools::*; + use env_info::EnvInfo; + use spec::*; + use transaction::*; + use util::log::init_log; + use trace::{FlatTrace, TraceError, trace}; + use types::executed::CallType; -#[test] -fn should_apply_create_transaction() { - init_log(); + #[test] + fn should_apply_create_transaction() { + init_log(); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Create, - value: 100.into(), - data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555").unwrap(), - }.sign(&"".sha3(), None); - - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - subtraces: 0, - action: trace::Action::Create(trace::Create { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - value: 100.into(), - gas: 77412.into(), - init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], - }), - result: trace::Res::Create(trace::CreateResult { - gas_used: U256::from(3224), - address: Address::from_str("8988167e088c87cd314df6d3c2b83da5acb93ace").unwrap(), - code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] - }), - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_work_when_cloned() { - init_log(); - - let a = Address::zero(); - - let temp = RandomTempPath::new(); - let mut state = { + let temp = RandomTempPath::new(); let mut state = get_temp_state_in(temp.as_path()); - assert_eq!(state.exists(&a), false); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Create, + value: 100.into(), + data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555").unwrap(), + }.sign(&"".sha3(), None); + + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + subtraces: 0, + action: trace::Action::Create(trace::Create { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + value: 100.into(), + gas: 77412.into(), + init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], + }), + result: trace::Res::Create(trace::CreateResult { + gas_used: U256::from(3224), + address: Address::from_str("8988167e088c87cd314df6d3c2b83da5acb93ace").unwrap(), + code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] + }), + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_work_when_cloned() { + init_log(); + + let a = Address::zero(); + + let temp = RandomTempPath::new(); + let mut state = { + let mut state = get_temp_state_in(temp.as_path()); + assert_eq!(state.exists(&a), false); + state.inc_nonce(&a); + state.commit().unwrap(); + state.clone() + }; + state.inc_nonce(&a); state.commit().unwrap(); - state.clone() - }; + } - state.inc_nonce(&a); - state.commit().unwrap(); -} + #[test] + fn should_trace_failed_create_transaction() { + init_log(); -#[test] -fn should_trace_failed_create_transaction() { - init_log(); + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Create, - value: 100.into(), - data: FromHex::from_hex("5b600056").unwrap(), - }.sign(&"".sha3(), None); - - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - action: trace::Action::Create(trace::Create { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Create, value: 100.into(), - gas: 78792.into(), - init: vec![91, 96, 0, 86], - }), - result: trace::Res::FailedCreate(TraceError::OutOfGas), - subtraces: 0 - }]; + data: FromHex::from_hex("5b600056").unwrap(), + }.sign(&"".sha3(), None); - assert_eq!(result.trace, expected_trace); -} + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + action: trace::Action::Create(trace::Create { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + value: 100.into(), + gas: 78792.into(), + init: vec![91, 96, 0, 86], + }), + result: trace::Res::FailedCreate(TraceError::OutOfGas), + subtraces: 0 + }]; -#[test] -fn should_trace_call_transaction() { - init_log(); + assert_eq!(result.trace, expected_trace); + } - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + #[test] + fn should_trace_call_transaction() { + init_log(); - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 100.into(), - data: vec![], - }.sign(&"".sha3(), None); + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); - state.init_code(&0xa.into(), FromHex::from_hex("6000").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), value: 100.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(3), - output: vec![] - }), - subtraces: 0, - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_trace_basic_call_transaction() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 100.into(), - data: vec![], - }.sign(&"".sha3(), None); - - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 100.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(0), - output: vec![] - }), - subtraces: 0, - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_trace_call_transaction_to_builtin() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = &*Spec::new_test().engine; - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0x1.into()), - value: 0.into(), - data: vec![], - }.sign(&"".sha3(), None); - - let result = state.apply(&info, engine, &t, true).unwrap(); - - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: "0000000000000000000000000000000000000001".into(), - value: 0.into(), - gas: 79_000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(3000), - output: vec![] - }), - subtraces: 0, - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_not_trace_subcall_transaction_to_builtin() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = &*Spec::new_test().engine; - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 0.into(), - data: vec![], - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060006001610be0f1").unwrap()); - let result = state.apply(&info, engine, &t, true).unwrap(); - - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 0.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(28_061), - output: vec![] - }), - subtraces: 0, - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_not_trace_callcode() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = &*Spec::new_test().engine; - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 0.into(), - data: vec![], - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b611000f2").unwrap()); - state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); - let result = state.apply(&info, engine, &t, true).unwrap(); - - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - subtraces: 1, - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 0.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: 64.into(), - output: vec![] - }), - }, FlatTrace { - trace_address: vec![0].into_iter().collect(), - subtraces: 0, - action: trace::Action::Call(trace::Call { - from: 0xa.into(), - to: 0xa.into(), - value: 0.into(), - gas: 4096.into(), - input: vec![], - call_type: CallType::CallCode, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: 3.into(), - output: vec![], - }), - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_not_trace_delegatecall() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - info.number = 0x789b0; - let engine = &*Spec::new_test().engine; - - println!("schedule.have_delegate_call: {:?}", engine.schedule(&info).have_delegate_call); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 0.into(), - data: vec![], - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("6000600060006000600b618000f4").unwrap()); - state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); - let result = state.apply(&info, engine, &t, true).unwrap(); - - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - subtraces: 1, - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 0.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(61), - output: vec![] - }), - }, FlatTrace { - trace_address: vec![0].into_iter().collect(), - subtraces: 0, - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 0.into(), - gas: 32768.into(), - input: vec![], - call_type: CallType::DelegateCall, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: 3.into(), - output: vec![], - }), - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_trace_failed_call_transaction() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 100.into(), - data: vec![], - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("5b600056").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 100.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::FailedCall(TraceError::OutOfGas), - subtraces: 0, - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_trace_call_with_subcall_transaction() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 100.into(), - data: vec![], - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); - state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - subtraces: 1, - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 100.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(69), - output: vec![] - }), - }, FlatTrace { - trace_address: vec![0].into_iter().collect(), - subtraces: 0, - action: trace::Action::Call(trace::Call { - from: 0xa.into(), - to: 0xb.into(), - value: 0.into(), - gas: 78934.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(3), - output: vec![] - }), - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_trace_call_with_basic_subcall_transaction() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 100.into(), - data: vec![], - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006045600b6000f1").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - subtraces: 1, - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 100.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(31761), - output: vec![] - }), - }, FlatTrace { - trace_address: vec![0].into_iter().collect(), - subtraces: 0, - action: trace::Action::Call(trace::Call { - from: 0xa.into(), - to: 0xb.into(), - value: 69.into(), - gas: 2300.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult::default()), - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_not_trace_call_with_invalid_basic_subcall_transaction() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 100.into(), - data: vec![], - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()); // not enough funds. - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - subtraces: 0, - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 100.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(31761), - output: vec![] - }), - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_trace_failed_subcall_transaction() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 100.into(), - data: vec![],//600480600b6000396000f35b600056 - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); - state.init_code(&0xb.into(), FromHex::from_hex("5b600056").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - subtraces: 1, - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 100.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(79_000), - output: vec![] - }), - }, FlatTrace { - trace_address: vec![0].into_iter().collect(), - subtraces: 0, - action: trace::Action::Call(trace::Call { - from: 0xa.into(), - to: 0xb.into(), - value: 0.into(), - gas: 78934.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::FailedCall(TraceError::OutOfGas), - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_trace_call_with_subcall_with_subcall_transaction() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 100.into(), - data: vec![], - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); - state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap()); - state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - subtraces: 1, - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 100.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(135), - output: vec![] - }), - }, FlatTrace { - trace_address: vec![0].into_iter().collect(), - subtraces: 1, - action: trace::Action::Call(trace::Call { - from: 0xa.into(), - to: 0xb.into(), - value: 0.into(), - gas: 78934.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(69), - output: vec![] - }), - }, FlatTrace { - trace_address: vec![0, 0].into_iter().collect(), - subtraces: 0, - action: trace::Action::Call(trace::Call { - from: 0xb.into(), - to: 0xc.into(), - value: 0.into(), - gas: 78868.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(3), - output: vec![] - }), - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_trace_failed_subcall_with_subcall_transaction() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 100.into(), - data: vec![],//600480600b6000396000f35b600056 - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); - state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap()); - state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - subtraces: 1, - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 100.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(79_000), - output: vec![] - }) - }, FlatTrace { - trace_address: vec![0].into_iter().collect(), - subtraces: 1, + data: vec![], + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("6000").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), action: trace::Action::Call(trace::Call { - from: 0xa.into(), - to: 0xb.into(), - value: 0.into(), - gas: 78934.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::FailedCall(TraceError::OutOfGas), - }, FlatTrace { - trace_address: vec![0, 0].into_iter().collect(), - subtraces: 0, - action: trace::Action::Call(trace::Call { - from: 0xb.into(), - to: 0xc.into(), - value: 0.into(), - gas: 78868.into(), - call_type: CallType::Call, - input: vec![], - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(3), - output: vec![] - }), - }]; + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(3), + output: vec![] + }), + subtraces: 0, + }]; - assert_eq!(result.trace, expected_trace); -} + assert_eq!(result.trace, expected_trace); + } -#[test] -fn should_trace_suicide() { - init_log(); + #[test] + fn should_trace_basic_call_transaction() { + init_log(); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 100.into(), - data: vec![], - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("73000000000000000000000000000000000000000bff").unwrap()); - state.add_balance(&0xa.into(), &50.into(), CleanupMode::NoEmpty); - state.add_balance(t.sender().as_ref().unwrap(), &100.into(), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - subtraces: 1, - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), value: 100.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: 3.into(), - output: vec![] - }), - }, FlatTrace { - trace_address: vec![0].into_iter().collect(), - subtraces: 0, - action: trace::Action::Suicide(trace::Suicide { - address: 0xa.into(), - refund_address: 0xb.into(), - balance: 150.into(), - }), - result: trace::Res::None, - }]; + data: vec![], + }.sign(&"".sha3(), None); - assert_eq!(result.trace, expected_trace); -} + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(0), + output: vec![] + }), + subtraces: 0, + }]; -#[test] -fn code_from_database() { - let a = Address::zero(); - let temp = RandomTempPath::new(); - let (root, db) = { + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_trace_call_transaction_to_builtin() { + init_log(); + + let temp = RandomTempPath::new(); let mut state = get_temp_state_in(temp.as_path()); - state.require_or_from(&a, false, ||Account::new_contract(42.into(), 0.into()), |_|{}); - state.init_code(&a, vec![1, 2, 3]); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = &*Spec::new_test().engine; + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0x1.into()), + value: 0.into(), + data: vec![], + }.sign(&"".sha3(), None); + + let result = state.apply(&info, engine, &t, true).unwrap(); + + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: "0000000000000000000000000000000000000001".into(), + value: 0.into(), + gas: 79_000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(3000), + output: vec![] + }), + subtraces: 0, + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_not_trace_subcall_transaction_to_builtin() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = &*Spec::new_test().engine; + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 0.into(), + data: vec![], + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060006001610be0f1").unwrap()); + let result = state.apply(&info, engine, &t, true).unwrap(); + + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 0.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(28_061), + output: vec![] + }), + subtraces: 0, + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_not_trace_callcode() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = &*Spec::new_test().engine; + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 0.into(), + data: vec![], + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b611000f2").unwrap()); + state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); + let result = state.apply(&info, engine, &t, true).unwrap(); + + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + subtraces: 1, + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 0.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: 64.into(), + output: vec![] + }), + }, FlatTrace { + trace_address: vec![0].into_iter().collect(), + subtraces: 0, + action: trace::Action::Call(trace::Call { + from: 0xa.into(), + to: 0xa.into(), + value: 0.into(), + gas: 4096.into(), + input: vec![], + call_type: CallType::CallCode, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: 3.into(), + output: vec![], + }), + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_not_trace_delegatecall() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + info.number = 0x789b0; + let engine = &*Spec::new_test().engine; + + println!("schedule.have_delegate_call: {:?}", engine.schedule(&info).have_delegate_call); + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 0.into(), + data: vec![], + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("6000600060006000600b618000f4").unwrap()); + state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); + let result = state.apply(&info, engine, &t, true).unwrap(); + + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + subtraces: 1, + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 0.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(61), + output: vec![] + }), + }, FlatTrace { + trace_address: vec![0].into_iter().collect(), + subtraces: 0, + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 0.into(), + gas: 32768.into(), + input: vec![], + call_type: CallType::DelegateCall, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: 3.into(), + output: vec![], + }), + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_trace_failed_call_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), + data: vec![], + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("5b600056").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::FailedCall(TraceError::OutOfGas), + subtraces: 0, + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_trace_call_with_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), + data: vec![], + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + subtraces: 1, + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(69), + output: vec![] + }), + }, FlatTrace { + trace_address: vec![0].into_iter().collect(), + subtraces: 0, + action: trace::Action::Call(trace::Call { + from: 0xa.into(), + to: 0xb.into(), + value: 0.into(), + gas: 78934.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(3), + output: vec![] + }), + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_trace_call_with_basic_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), + data: vec![], + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006045600b6000f1").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + subtraces: 1, + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(31761), + output: vec![] + }), + }, FlatTrace { + trace_address: vec![0].into_iter().collect(), + subtraces: 0, + action: trace::Action::Call(trace::Call { + from: 0xa.into(), + to: 0xb.into(), + value: 69.into(), + gas: 2300.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult::default()), + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_not_trace_call_with_invalid_basic_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), + data: vec![], + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()); // not enough funds. + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + subtraces: 0, + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(31761), + output: vec![] + }), + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_trace_failed_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), + data: vec![],//600480600b6000396000f35b600056 + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&0xb.into(), FromHex::from_hex("5b600056").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + subtraces: 1, + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(79_000), + output: vec![] + }), + }, FlatTrace { + trace_address: vec![0].into_iter().collect(), + subtraces: 0, + action: trace::Action::Call(trace::Call { + from: 0xa.into(), + to: 0xb.into(), + value: 0.into(), + gas: 78934.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::FailedCall(TraceError::OutOfGas), + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_trace_call_with_subcall_with_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), + data: vec![], + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap()); + state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + subtraces: 1, + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(135), + output: vec![] + }), + }, FlatTrace { + trace_address: vec![0].into_iter().collect(), + subtraces: 1, + action: trace::Action::Call(trace::Call { + from: 0xa.into(), + to: 0xb.into(), + value: 0.into(), + gas: 78934.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(69), + output: vec![] + }), + }, FlatTrace { + trace_address: vec![0, 0].into_iter().collect(), + subtraces: 0, + action: trace::Action::Call(trace::Call { + from: 0xb.into(), + to: 0xc.into(), + value: 0.into(), + gas: 78868.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(3), + output: vec![] + }), + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_trace_failed_subcall_with_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), + data: vec![],//600480600b6000396000f35b600056 + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap()); + state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + subtraces: 1, + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(79_000), + output: vec![] + }) + }, FlatTrace { + trace_address: vec![0].into_iter().collect(), + subtraces: 1, + action: trace::Action::Call(trace::Call { + from: 0xa.into(), + to: 0xb.into(), + value: 0.into(), + gas: 78934.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::FailedCall(TraceError::OutOfGas), + }, FlatTrace { + trace_address: vec![0, 0].into_iter().collect(), + subtraces: 0, + action: trace::Action::Call(trace::Call { + from: 0xb.into(), + to: 0xc.into(), + value: 0.into(), + gas: 78868.into(), + call_type: CallType::Call, + input: vec![], + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(3), + output: vec![] + }), + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_trace_suicide() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), + data: vec![], + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("73000000000000000000000000000000000000000bff").unwrap()); + state.add_balance(&0xa.into(), &50.into(), CleanupMode::NoEmpty); + state.add_balance(t.sender().as_ref().unwrap(), &100.into(), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + subtraces: 1, + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: 3.into(), + output: vec![] + }), + }, FlatTrace { + trace_address: vec![0].into_iter().collect(), + subtraces: 0, + action: trace::Action::Suicide(trace::Suicide { + address: 0xa.into(), + refund_address: 0xb.into(), + balance: 150.into(), + }), + result: trace::Res::None, + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn code_from_database() { + let a = Address::zero(); + let temp = RandomTempPath::new(); + let (root, db) = { + let mut state = get_temp_state_in(temp.as_path()); + state.require_or_from(&a, false, ||Account::new_contract(42.into(), 0.into()), |_|{}); + state.init_code(&a, vec![1, 2, 3]); + assert_eq!(state.code(&a), Some(Arc::new([1u8, 2, 3].to_vec()))); + state.commit().unwrap(); + assert_eq!(state.code(&a), Some(Arc::new([1u8, 2, 3].to_vec()))); + state.drop() + }; + + let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); assert_eq!(state.code(&a), Some(Arc::new([1u8, 2, 3].to_vec()))); - state.commit().unwrap(); - assert_eq!(state.code(&a), Some(Arc::new([1u8, 2, 3].to_vec()))); - state.drop() - }; + } - let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); - assert_eq!(state.code(&a), Some(Arc::new([1u8, 2, 3].to_vec()))); -} + #[test] + fn storage_at_from_database() { + let a = Address::zero(); + let temp = RandomTempPath::new(); + let (root, db) = { + let mut state = get_temp_state_in(temp.as_path()); + state.set_storage(&a, H256::from(&U256::from(1u64)), H256::from(&U256::from(69u64))); + state.commit().unwrap(); + state.drop() + }; -#[test] -fn storage_at_from_database() { - let a = Address::zero(); - let temp = RandomTempPath::new(); - let (root, db) = { - let mut state = get_temp_state_in(temp.as_path()); - state.set_storage(&a, H256::from(&U256::from(1u64)), H256::from(&U256::from(69u64))); - state.commit().unwrap(); - state.drop() - }; + let s = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); + assert_eq!(s.storage_at(&a, &H256::from(&U256::from(1u64))), H256::from(&U256::from(69u64))); + } - let s = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); - assert_eq!(s.storage_at(&a, &H256::from(&U256::from(1u64))), H256::from(&U256::from(69u64))); -} + #[test] + fn get_from_database() { + let a = Address::zero(); + let temp = RandomTempPath::new(); + let (root, db) = { + let mut state = get_temp_state_in(temp.as_path()); + state.inc_nonce(&a); + state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty); + state.commit().unwrap(); + assert_eq!(state.balance(&a), U256::from(69u64)); + state.drop() + }; -#[test] -fn get_from_database() { - let a = Address::zero(); - let temp = RandomTempPath::new(); - let (root, db) = { - let mut state = get_temp_state_in(temp.as_path()); - state.inc_nonce(&a); - state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty); - state.commit().unwrap(); + let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); assert_eq!(state.balance(&a), U256::from(69u64)); - state.drop() - }; - - let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); - assert_eq!(state.balance(&a), U256::from(69u64)); - assert_eq!(state.nonce(&a), U256::from(1u64)); -} - -#[test] -fn remove() { - let a = Address::zero(); - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); - assert_eq!(state.exists(&a), false); - assert_eq!(state.exists_and_not_null(&a), false); - state.inc_nonce(&a); - assert_eq!(state.exists(&a), true); - assert_eq!(state.exists_and_not_null(&a), true); - assert_eq!(state.nonce(&a), U256::from(1u64)); - state.kill_account(&a); - assert_eq!(state.exists(&a), false); - assert_eq!(state.exists_and_not_null(&a), false); - assert_eq!(state.nonce(&a), U256::from(0u64)); -} - -#[test] -fn empty_account_is_not_created() { - let a = Address::zero(); - let path = RandomTempPath::new(); - let db = get_temp_state_db_in(path.as_path()); - let (root, db) = { - let mut state = State::new(db, U256::from(0), Default::default()); - state.add_balance(&a, &U256::default(), CleanupMode::NoEmpty); // create an empty account - state.commit().unwrap(); - state.drop() - }; - let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); - assert!(!state.exists(&a)); - assert!(!state.exists_and_not_null(&a)); -} - -#[test] -fn empty_account_exists_when_creation_forced() { - let a = Address::zero(); - let path = RandomTempPath::new(); - let db = get_temp_state_db_in(path.as_path()); - let (root, db) = { - let mut state = State::new(db, U256::from(0), Default::default()); - state.add_balance(&a, &U256::default(), CleanupMode::ForceCreate); // create an empty account - state.commit().unwrap(); - state.drop() - }; - let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); - assert!(state.exists(&a)); - assert!(!state.exists_and_not_null(&a)); -} - -#[test] -fn remove_from_database() { - let a = Address::zero(); - let temp = RandomTempPath::new(); - let (root, db) = { - let mut state = get_temp_state_in(temp.as_path()); - state.inc_nonce(&a); - state.commit().unwrap(); - assert_eq!(state.exists(&a), true); assert_eq!(state.nonce(&a), U256::from(1u64)); - state.drop() - }; + } - let (root, db) = { - let mut state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); + #[test] + fn remove() { + let a = Address::zero(); + let mut state_result = get_temp_state(); + let mut state = state_result.reference_mut(); + assert_eq!(state.exists(&a), false); + assert_eq!(state.exists_and_not_null(&a), false); + state.inc_nonce(&a); assert_eq!(state.exists(&a), true); + assert_eq!(state.exists_and_not_null(&a), true); assert_eq!(state.nonce(&a), U256::from(1u64)); state.kill_account(&a); - state.commit().unwrap(); + assert_eq!(state.exists(&a), false); + assert_eq!(state.exists_and_not_null(&a), false); + assert_eq!(state.nonce(&a), U256::from(0u64)); + } + + #[test] + fn empty_account_is_not_created() { + let a = Address::zero(); + let path = RandomTempPath::new(); + let db = get_temp_state_db_in(path.as_path()); + let (root, db) = { + let mut state = State::new(db, U256::from(0), Default::default()); + state.add_balance(&a, &U256::default(), CleanupMode::NoEmpty); // create an empty account + state.commit().unwrap(); + state.drop() + }; + let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); + assert!(!state.exists(&a)); + assert!(!state.exists_and_not_null(&a)); + } + + #[test] + fn empty_account_exists_when_creation_forced() { + let a = Address::zero(); + let path = RandomTempPath::new(); + let db = get_temp_state_db_in(path.as_path()); + let (root, db) = { + let mut state = State::new(db, U256::from(0), Default::default()); + state.add_balance(&a, &U256::default(), CleanupMode::ForceCreate); // create an empty account + state.commit().unwrap(); + state.drop() + }; + let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); + assert!(state.exists(&a)); + assert!(!state.exists_and_not_null(&a)); + } + + #[test] + fn remove_from_database() { + let a = Address::zero(); + let temp = RandomTempPath::new(); + let (root, db) = { + let mut state = get_temp_state_in(temp.as_path()); + state.inc_nonce(&a); + state.commit().unwrap(); + assert_eq!(state.exists(&a), true); + assert_eq!(state.nonce(&a), U256::from(1u64)); + state.drop() + }; + + let (root, db) = { + let mut state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); + assert_eq!(state.exists(&a), true); + assert_eq!(state.nonce(&a), U256::from(1u64)); + state.kill_account(&a); + state.commit().unwrap(); + assert_eq!(state.exists(&a), false); + assert_eq!(state.nonce(&a), U256::from(0u64)); + state.drop() + }; + + let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); assert_eq!(state.exists(&a), false); assert_eq!(state.nonce(&a), U256::from(0u64)); - state.drop() - }; + } - let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); - assert_eq!(state.exists(&a), false); - assert_eq!(state.nonce(&a), U256::from(0u64)); -} + #[test] + fn alter_balance() { + let mut state_result = get_temp_state(); + let mut state = state_result.reference_mut(); + let a = Address::zero(); + let b = 1u64.into(); + state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty); + assert_eq!(state.balance(&a), U256::from(69u64)); + state.commit().unwrap(); + assert_eq!(state.balance(&a), U256::from(69u64)); + state.sub_balance(&a, &U256::from(42u64)); + assert_eq!(state.balance(&a), U256::from(27u64)); + state.commit().unwrap(); + assert_eq!(state.balance(&a), U256::from(27u64)); + state.transfer_balance(&a, &b, &U256::from(18u64), CleanupMode::NoEmpty); + assert_eq!(state.balance(&a), U256::from(9u64)); + assert_eq!(state.balance(&b), U256::from(18u64)); + state.commit().unwrap(); + assert_eq!(state.balance(&a), U256::from(9u64)); + assert_eq!(state.balance(&b), U256::from(18u64)); + } -#[test] -fn alter_balance() { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); - let a = Address::zero(); - let b = 1u64.into(); - state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty); - assert_eq!(state.balance(&a), U256::from(69u64)); - state.commit().unwrap(); - assert_eq!(state.balance(&a), U256::from(69u64)); - state.sub_balance(&a, &U256::from(42u64)); - assert_eq!(state.balance(&a), U256::from(27u64)); - state.commit().unwrap(); - assert_eq!(state.balance(&a), U256::from(27u64)); - state.transfer_balance(&a, &b, &U256::from(18u64), CleanupMode::NoEmpty); - assert_eq!(state.balance(&a), U256::from(9u64)); - assert_eq!(state.balance(&b), U256::from(18u64)); - state.commit().unwrap(); - assert_eq!(state.balance(&a), U256::from(9u64)); - assert_eq!(state.balance(&b), U256::from(18u64)); -} + #[test] + fn alter_nonce() { + let mut state_result = get_temp_state(); + let mut state = state_result.reference_mut(); + let a = Address::zero(); + state.inc_nonce(&a); + assert_eq!(state.nonce(&a), U256::from(1u64)); + state.inc_nonce(&a); + assert_eq!(state.nonce(&a), U256::from(2u64)); + state.commit().unwrap(); + assert_eq!(state.nonce(&a), U256::from(2u64)); + state.inc_nonce(&a); + assert_eq!(state.nonce(&a), U256::from(3u64)); + state.commit().unwrap(); + assert_eq!(state.nonce(&a), U256::from(3u64)); + } -#[test] -fn alter_nonce() { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); - let a = Address::zero(); - state.inc_nonce(&a); - assert_eq!(state.nonce(&a), U256::from(1u64)); - state.inc_nonce(&a); - assert_eq!(state.nonce(&a), U256::from(2u64)); - state.commit().unwrap(); - assert_eq!(state.nonce(&a), U256::from(2u64)); - state.inc_nonce(&a); - assert_eq!(state.nonce(&a), U256::from(3u64)); - state.commit().unwrap(); - assert_eq!(state.nonce(&a), U256::from(3u64)); -} + #[test] + fn balance_nonce() { + let mut state_result = get_temp_state(); + let mut state = state_result.reference_mut(); + let a = Address::zero(); + assert_eq!(state.balance(&a), U256::from(0u64)); + assert_eq!(state.nonce(&a), U256::from(0u64)); + state.commit().unwrap(); + assert_eq!(state.balance(&a), U256::from(0u64)); + assert_eq!(state.nonce(&a), U256::from(0u64)); + } -#[test] -fn balance_nonce() { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); - let a = Address::zero(); - assert_eq!(state.balance(&a), U256::from(0u64)); - assert_eq!(state.nonce(&a), U256::from(0u64)); - state.commit().unwrap(); - assert_eq!(state.balance(&a), U256::from(0u64)); - assert_eq!(state.nonce(&a), U256::from(0u64)); -} + #[test] + fn ensure_cached() { + let mut state_result = get_temp_state(); + let mut state = state_result.reference_mut(); + let a = Address::zero(); + state.require(&a, false); + state.commit().unwrap(); + assert_eq!(state.root().hex(), "0ce23f3c809de377b008a4a3ee94a0834aac8bec1f86e28ffe4fdb5a15b0c785"); + } -#[test] -fn ensure_cached() { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); - let a = Address::zero(); - state.require(&a, false); - state.commit().unwrap(); - assert_eq!(state.root().hex(), "0ce23f3c809de377b008a4a3ee94a0834aac8bec1f86e28ffe4fdb5a15b0c785"); -} + #[test] + fn checkpoint_basic() { + let mut state_result = get_temp_state(); + let mut state = state_result.reference_mut(); + let a = Address::zero(); + state.checkpoint(); + state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty); + assert_eq!(state.balance(&a), U256::from(69u64)); + state.discard_checkpoint(); + assert_eq!(state.balance(&a), U256::from(69u64)); + state.checkpoint(); + state.add_balance(&a, &U256::from(1u64), CleanupMode::NoEmpty); + assert_eq!(state.balance(&a), U256::from(70u64)); + state.revert_to_checkpoint(); + assert_eq!(state.balance(&a), U256::from(69u64)); + } -#[test] -fn checkpoint_basic() { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); - let a = Address::zero(); - state.checkpoint(); - state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty); - assert_eq!(state.balance(&a), U256::from(69u64)); - state.discard_checkpoint(); - assert_eq!(state.balance(&a), U256::from(69u64)); - state.checkpoint(); - state.add_balance(&a, &U256::from(1u64), CleanupMode::NoEmpty); - assert_eq!(state.balance(&a), U256::from(70u64)); - state.revert_to_checkpoint(); - assert_eq!(state.balance(&a), U256::from(69u64)); -} + #[test] + fn checkpoint_nested() { + let mut state_result = get_temp_state(); + let mut state = state_result.reference_mut(); + let a = Address::zero(); + state.checkpoint(); + state.checkpoint(); + state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty); + assert_eq!(state.balance(&a), U256::from(69u64)); + state.discard_checkpoint(); + assert_eq!(state.balance(&a), U256::from(69u64)); + state.revert_to_checkpoint(); + assert_eq!(state.balance(&a), U256::from(0)); + } -#[test] -fn checkpoint_nested() { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); - let a = Address::zero(); - state.checkpoint(); - state.checkpoint(); - state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty); - assert_eq!(state.balance(&a), U256::from(69u64)); - state.discard_checkpoint(); - assert_eq!(state.balance(&a), U256::from(69u64)); - state.revert_to_checkpoint(); - assert_eq!(state.balance(&a), U256::from(0)); -} + #[test] + fn create_empty() { + let mut state_result = get_temp_state(); + let mut state = state_result.reference_mut(); + state.commit().unwrap(); + assert_eq!(state.root().hex(), "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); + } -#[test] -fn create_empty() { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); - state.commit().unwrap(); - assert_eq!(state.root().hex(), "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); -} + #[test] + fn should_not_panic_on_state_diff_with_storage() { + let state = get_temp_state(); + let mut state = state.reference().clone(); -#[test] -fn should_not_panic_on_state_diff_with_storage() { - let state = get_temp_state(); - let mut state = state.reference().clone(); + let a: Address = 0xa.into(); + state.init_code(&a, b"abcdefg".to_vec()); + state.add_balance(&a, &256.into(), CleanupMode::NoEmpty); + state.set_storage(&a, 0xb.into(), 0xc.into()); - let a: Address = 0xa.into(); - state.init_code(&a, b"abcdefg".to_vec()); - state.add_balance(&a, &256.into(), CleanupMode::NoEmpty); - state.set_storage(&a, 0xb.into(), 0xc.into()); + let mut new_state = state.clone(); + new_state.set_storage(&a, 0xb.into(), 0xd.into()); - let mut new_state = state.clone(); - new_state.set_storage(&a, 0xb.into(), 0xd.into()); - - new_state.diff_from(state); -} + new_state.diff_from(state); + } } diff --git a/ethcore/src/state/substate.rs b/ethcore/src/state/substate.rs index 853b0e422..c11f802a1 100644 --- a/ethcore/src/state/substate.rs +++ b/ethcore/src/state/substate.rs @@ -57,6 +57,7 @@ impl Substate { } /// Get the cleanup mode object from this. + #[cfg_attr(feature="dev", allow(wrong_self_convention))] pub fn to_cleanup_mode(&mut self, schedule: &Schedule) -> CleanupMode { match (schedule.no_empty, schedule.kill_empty) { (false, _) => CleanupMode::ForceCreate, diff --git a/ethcore/src/state_db.rs b/ethcore/src/state_db.rs index 3a3595a35..eafa4022e 100644 --- a/ethcore/src/state_db.rs +++ b/ethcore/src/state_db.rs @@ -397,6 +397,7 @@ impl StateDB { } /// Get cached code based on hash. + #[cfg_attr(feature="dev", allow(map_clone))] pub fn get_cached_code(&self, hash: &H256) -> Option>> { let mut cache = self.code_cache.lock(); diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 99b251d66..427082823 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -62,7 +62,7 @@ fn should_return_registrar() { &db_config ).unwrap(); let params = client.additional_params(); - let address = params.get("registrar").unwrap(); + let address = ¶ms["registrar"]; assert_eq!(address.len(), 40); assert!(U256::from_str(address).is_ok()); @@ -93,7 +93,7 @@ fn imports_good_block() { &db_config ).unwrap(); let good_block = get_good_dummy_block(); - if let Err(_) = client.import_block(good_block) { + if client.import_block(good_block).is_err() { panic!("error importing block being good by definition"); } client.flush_queue(); @@ -203,18 +203,18 @@ fn can_collect_garbage() { #[test] fn can_generate_gas_price_median() { - let client_result = generate_dummy_client_with_data(3, 1, &vec_into![1, 2, 3]); + let client_result = generate_dummy_client_with_data(3, 1, slice_into![1, 2, 3]); let client = client_result.reference(); assert_eq!(Some(U256::from(2)), client.gas_price_median(3)); - let client_result = generate_dummy_client_with_data(4, 1, &vec_into![1, 4, 3, 2]); + let client_result = generate_dummy_client_with_data(4, 1, slice_into![1, 4, 3, 2]); let client = client_result.reference(); assert_eq!(Some(U256::from(3)), client.gas_price_median(4)); } #[test] fn can_generate_gas_price_histogram() { - let client_result = generate_dummy_client_with_data(20, 1, &vec_into![6354,8593,6065,4842,7845,7002,689,4958,4250,6098,5804,4320,643,8895,2296,8589,7145,2000,2512,1408]); + let client_result = generate_dummy_client_with_data(20, 1, slice_into![6354,8593,6065,4842,7845,7002,689,4958,4250,6098,5804,4320,643,8895,2296,8589,7145,2000,2512,1408]); let client = client_result.reference(); let hist = client.gas_price_histogram(20, 5).unwrap(); @@ -224,7 +224,7 @@ fn can_generate_gas_price_histogram() { #[test] fn empty_gas_price_histogram() { - let client_result = generate_dummy_client_with_data(20, 0, &vec_into![]); + let client_result = generate_dummy_client_with_data(20, 0, slice_into![]); let client = client_result.reference(); assert!(client.gas_price_histogram(20, 5).is_none()); diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index adfb4f096..77a6f117a 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -18,6 +18,7 @@ use ethkey::KeyPair; use io::*; use client::{BlockChainClient, Client, ClientConfig}; use util::*; +use util::trie::TrieSpec; use spec::*; use state_db::StateDB; use block::{OpenBlock, Drain}; @@ -157,7 +158,7 @@ pub fn generate_dummy_client_with_spec_and_data(get_test_spec: F, block_numbe let mut db_result = get_temp_state_db(); let mut db = db_result.take(); - test_spec.ensure_db_good(&mut db).unwrap(); + test_spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); let genesis_header = test_spec.genesis_header(); let mut rolling_timestamp = 40; @@ -262,7 +263,7 @@ pub fn get_test_client_with_blocks(blocks: Vec) -> GuardedTempResult TraceDB where T: DatabaseExtras { /// Creates new instance of `TraceDB`. pub fn new(config: Config, tracesdb: Arc, extras: Arc) -> Self { let mut batch = DBTransaction::new(&tracesdb); + let genesis = extras.block_hash(0) + .expect("Genesis block is always inserted upon extras db creation qed"); + batch.write(db::COL_TRACE, &genesis, &FlatBlockTraces::default()); batch.put(db::COL_TRACE, b"version", TRACE_DB_VER); tracesdb.write(batch).expect("failed to update version"); @@ -413,8 +416,12 @@ mod tests { struct NoopExtras; impl DatabaseExtras for NoopExtras { - fn block_hash(&self, _block_number: BlockNumber) -> Option { - unimplemented!(); + fn block_hash(&self, block_number: BlockNumber) -> Option { + if block_number == 0 { + Some(H256::default()) + } else { + unimplemented!() + } } fn transaction_hash(&self, _block_number: BlockNumber, _tx_position: usize) -> Option { @@ -581,35 +588,21 @@ mod tests { let db = Arc::new(Database::open(&DatabaseConfig::with_columns(::db::NUM_COLUMNS), temp.as_str()).unwrap()); let mut config = Config::default(); config.enabled = true; - let block_0 = H256::from(0xa1); - let block_1 = H256::from(0xa2); - let tx_0 = H256::from(0xff); - let tx_1 = H256::from(0xaf); + let block_1 = H256::from(0xa1); + let block_2 = H256::from(0xa2); + let tx_1 = H256::from(0xff); + let tx_2 = H256::from(0xaf); let mut extras = Extras::default(); - extras.block_hashes.insert(0, block_0.clone()); + extras.block_hashes.insert(0, H256::default()); + extras.block_hashes.insert(1, block_1.clone()); - extras.transaction_hashes.insert(0, vec![tx_0.clone()]); + extras.block_hashes.insert(2, block_2.clone()); extras.transaction_hashes.insert(1, vec![tx_1.clone()]); + extras.transaction_hashes.insert(2, vec![tx_2.clone()]); let tracedb = TraceDB::new(config, db.clone(), Arc::new(extras)); - // import block 0 - let request = create_simple_import_request(0, block_0.clone()); - let mut batch = DBTransaction::new(&db); - tracedb.import(&mut batch, request); - db.write(batch).unwrap(); - - let filter = Filter { - range: (0..0), - from_address: AddressesFilter::from(vec![Address::from(1)]), - to_address: AddressesFilter::from(vec![]), - }; - - let traces = tracedb.filter(&filter); - assert_eq!(traces.len(), 1); - assert_eq!(traces[0], create_simple_localized_trace(0, block_0.clone(), tx_0.clone())); - // import block 1 let request = create_simple_import_request(1, block_1.clone()); let mut batch = DBTransaction::new(&db); @@ -617,38 +610,56 @@ mod tests { db.write(batch).unwrap(); let filter = Filter { - range: (0..1), + range: (1..1), + from_address: AddressesFilter::from(vec![Address::from(1)]), + to_address: AddressesFilter::from(vec![]), + }; + + let traces = tracedb.filter(&filter); + assert_eq!(traces.len(), 1); + assert_eq!(traces[0], create_simple_localized_trace(1, block_1.clone(), tx_1.clone())); + + // import block 2 + let request = create_simple_import_request(2, block_2.clone()); + let mut batch = DBTransaction::new(&db); + tracedb.import(&mut batch, request); + db.write(batch).unwrap(); + + let filter = Filter { + range: (1..2), from_address: AddressesFilter::from(vec![Address::from(1)]), to_address: AddressesFilter::from(vec![]), }; let traces = tracedb.filter(&filter); assert_eq!(traces.len(), 2); - assert_eq!(traces[0], create_simple_localized_trace(0, block_0.clone(), tx_0.clone())); - assert_eq!(traces[1], create_simple_localized_trace(1, block_1.clone(), tx_1.clone())); + assert_eq!(traces[0], create_simple_localized_trace(1, block_1.clone(), tx_1.clone())); + assert_eq!(traces[1], create_simple_localized_trace(2, block_2.clone(), tx_2.clone())); - let traces = tracedb.block_traces(0).unwrap(); - assert_eq!(traces.len(), 1); - assert_eq!(traces[0], create_simple_localized_trace(0, block_0.clone(), tx_0.clone())); + assert!(tracedb.block_traces(0).is_some(), "Genesis trace should be always present."); let traces = tracedb.block_traces(1).unwrap(); assert_eq!(traces.len(), 1); assert_eq!(traces[0], create_simple_localized_trace(1, block_1.clone(), tx_1.clone())); - assert_eq!(None, tracedb.block_traces(2)); - - let traces = tracedb.transaction_traces(0, 0).unwrap(); + let traces = tracedb.block_traces(2).unwrap(); assert_eq!(traces.len(), 1); - assert_eq!(traces[0], create_simple_localized_trace(0, block_0.clone(), tx_0.clone())); + assert_eq!(traces[0], create_simple_localized_trace(2, block_2.clone(), tx_2.clone())); + + assert_eq!(None, tracedb.block_traces(3)); let traces = tracedb.transaction_traces(1, 0).unwrap(); assert_eq!(traces.len(), 1); assert_eq!(traces[0], create_simple_localized_trace(1, block_1.clone(), tx_1.clone())); - assert_eq!(None, tracedb.transaction_traces(1, 1)); + let traces = tracedb.transaction_traces(2, 0).unwrap(); + assert_eq!(traces.len(), 1); + assert_eq!(traces[0], create_simple_localized_trace(2, block_2.clone(), tx_2.clone())); + + assert_eq!(None, tracedb.transaction_traces(2, 1)); - assert_eq!(tracedb.trace(0, 0, vec![]).unwrap(), create_simple_localized_trace(0, block_0.clone(), tx_0.clone())); assert_eq!(tracedb.trace(1, 0, vec![]).unwrap(), create_simple_localized_trace(1, block_1.clone(), tx_1.clone())); + assert_eq!(tracedb.trace(2, 0, vec![]).unwrap(), create_simple_localized_trace(2, block_2.clone(), tx_2.clone())); } #[test] @@ -660,8 +671,10 @@ mod tests { let block_0 = H256::from(0xa1); let tx_0 = H256::from(0xff); - extras.block_hashes.insert(0, block_0.clone()); - extras.transaction_hashes.insert(0, vec![tx_0.clone()]); + extras.block_hashes.insert(0, H256::default()); + extras.transaction_hashes.insert(0, vec![]); + extras.block_hashes.insert(1, block_0.clone()); + extras.transaction_hashes.insert(1, vec![tx_0.clone()]); // set tracing on config.enabled = true; @@ -669,8 +682,8 @@ mod tests { { let tracedb = TraceDB::new(config.clone(), db.clone(), Arc::new(extras.clone())); - // import block 0 - let request = create_simple_import_request(0, block_0.clone()); + // import block 1 + let request = create_simple_import_request(1, block_0.clone()); let mut batch = DBTransaction::new(&db); tracedb.import(&mut batch, request); db.write(batch).unwrap(); @@ -678,8 +691,28 @@ mod tests { { let tracedb = TraceDB::new(config.clone(), db.clone(), Arc::new(extras)); - let traces = tracedb.transaction_traces(0, 0); - assert_eq!(traces.unwrap(), vec![create_simple_localized_trace(0, block_0, tx_0)]); + let traces = tracedb.transaction_traces(1, 0); + assert_eq!(traces.unwrap(), vec![create_simple_localized_trace(1, block_0, tx_0)]); } } + + #[test] + fn query_genesis() { + let temp = RandomTempPath::new(); + let db = new_db(temp.as_str()); + let mut config = Config::default(); + let mut extras = Extras::default(); + let block_0 = H256::from(0xa1); + + extras.block_hashes.insert(0, block_0.clone()); + extras.transaction_hashes.insert(0, vec![]); + + // set tracing on + config.enabled = true; + + let tracedb = TraceDB::new(config.clone(), db.clone(), Arc::new(extras.clone())); + let traces = tracedb.block_traces(0).unwrap(); + + assert_eq!(traces.len(), 0); + } } diff --git a/ethcore/src/types/mode.rs b/ethcore/src/types/mode.rs index 58f652c6c..dff75e158 100644 --- a/ethcore/src/types/mode.rs +++ b/ethcore/src/types/mode.rs @@ -19,16 +19,16 @@ pub use std::time::Duration; use client::Mode as ClientMode; -/// IPC-capable shadow-type for client::config::Mode +/// IPC-capable shadow-type for `client::config::Mode` #[derive(Clone, Binary, Debug)] pub enum Mode { - /// Same as ClientMode::Off. + /// Same as `ClientMode::Off`. Off, - /// Same as ClientMode::Dark; values in seconds. + /// Same as `ClientMode::Dark`; values in seconds. Dark(u64), - /// Same as ClientMode::Passive; values in seconds. + /// Same as `ClientMode::Passive`; values in seconds. Passive(u64, u64), - /// Same as ClientMode::Active. + /// Same as `ClientMode::Active`. Active, } @@ -52,4 +52,4 @@ impl From for ClientMode { Mode::Active => ClientMode::Active, } } -} \ No newline at end of file +} diff --git a/ethcore/src/types/trace_types/flat.rs b/ethcore/src/types/trace_types/flat.rs index 58983558d..d0c7cbe9b 100644 --- a/ethcore/src/types/trace_types/flat.rs +++ b/ethcore/src/types/trace_types/flat.rs @@ -119,7 +119,7 @@ impl Into> for FlatTransactionTraces { } /// Represents all traces produced by transactions in a single block. -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, Default)] pub struct FlatBlockTraces(Vec); impl HeapSizeOf for FlatBlockTraces { diff --git a/ethcore/src/types/transaction.rs b/ethcore/src/types/transaction.rs index 8289c5864..7dba4da53 100644 --- a/ethcore/src/types/transaction.rs +++ b/ethcore/src/types/transaction.rs @@ -73,7 +73,7 @@ pub struct Transaction { impl Transaction { /// Append object with a without signature into RLP stream pub fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream, network_id: Option) { - s.begin_list(if let None = network_id { 6 } else { 9 }); + s.begin_list(if network_id.is_none() { 6 } else { 9 }); s.append(&self.nonce); s.append(&self.gas_price); s.append(&self.gas); @@ -210,7 +210,7 @@ pub struct SignedTransaction { /// Plain Transaction. unsigned: Transaction, /// The V field of the signature; the LS bit described which half of the curve our point falls - /// in. The MS bits describe which network this transaction is for. If 27/28, its for all networks. + /// in. The MS bits describe which network this transaction is for. If 27/28, its for all networks. v: u8, /// The R field of the signature; helps describe the point on the curve. r: U256, @@ -304,7 +304,7 @@ impl SignedTransaction { /// 0 if `v` would have been 27 under "Electrum" notation, 1 if 28 or 4 if invalid. pub fn standard_v(&self) -> u8 { match self.v { v if v == 27 || v == 28 || v > 36 => (v - 1) % 2, _ => 4 } } - /// The network ID, or `None` if this is a global transaction. + /// The network ID, or `None` if this is a global transaction. pub fn network_id(&self) -> Option { match self.v { v if v > 36 => Some((v - 35) / 2), @@ -461,7 +461,7 @@ fn should_agree_with_vitalik() { let signed: SignedTransaction = decode(&FromHex::from_hex(tx_data).unwrap()); signed.check_low_s().unwrap(); assert_eq!(signed.sender().unwrap(), address.into()); - flushln!("networkid: {:?}", signed.network_id()); + flushln!("networkid: {:?}", signed.network_id()); }; test_vector("f864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", "0xf0f6f18bca1b28cd68e4357452947e021241e9ce") @@ -474,4 +474,4 @@ fn should_agree_with_vitalik() { test_vector("f867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", "0xd37922162ab7cea97c97a87551ed02c9a38b7332") test_vector("f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", "0x9bddad43f934d313c2b79ca28a432dd2b7281029") test_vector("f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", "0x3c24d7329e92f84f08556ceb6df1cdb0104ca49f") -} \ No newline at end of file +} diff --git a/ethcore/src/verification/queue/mod.rs b/ethcore/src/verification/queue/mod.rs index 99e09784d..686a1d093 100644 --- a/ethcore/src/verification/queue/mod.rs +++ b/ethcore/src/verification/queue/mod.rs @@ -35,6 +35,9 @@ pub mod kind; const MIN_MEM_LIMIT: usize = 16384; const MIN_QUEUE_LIMIT: usize = 512; +// maximum possible number of verification threads. +const MAX_VERIFIERS: usize = 8; + /// Type alias for block queue convenience. pub type BlockQueue = VerificationQueue; @@ -61,6 +64,37 @@ impl Default for Config { } } +struct VerifierHandle { + deleting: Arc, + sleep: Arc, + thread: JoinHandle<()>, +} + +impl VerifierHandle { + // signal to the verifier thread that it should sleep. + fn sleep(&self) { + self.sleep.store(true, AtomicOrdering::SeqCst); + } + + // signal to the verifier thread that it should wake up. + fn wake_up(&self) { + self.sleep.store(false, AtomicOrdering::SeqCst); + self.thread.thread().unpark(); + } + + // signal to the verifier thread that it should conclude its + // operations. + fn conclude(&self) { + self.wake_up(); + self.deleting.store(true, AtomicOrdering::Release); + } + + // join the verifier thread. + fn join(self) { + self.thread.join().expect("Verifier thread panicked"); + } +} + /// An item which is in the process of being verified. pub struct Verifying { hash: H256, @@ -97,11 +131,12 @@ pub struct VerificationQueue { engine: Arc, more_to_verify: Arc, verification: Arc>, - verifiers: Vec>, + verifiers: Mutex<(Vec, usize)>, deleting: Arc, ready_signal: Arc, empty: Arc, processing: RwLock>, + ticks_since_adjustment: AtomicUsize, max_queue_size: usize, max_mem_use: usize, } @@ -157,6 +192,7 @@ struct Verification { more_to_verify: SMutex<()>, empty: SMutex<()>, sizes: Sizes, + check_seal: bool, } impl VerificationQueue { @@ -173,7 +209,8 @@ impl VerificationQueue { unverified: AtomicUsize::new(0), verifying: AtomicUsize::new(0), verified: AtomicUsize::new(0), - } + }, + check_seal: check_seal, }); let more_to_verify = Arc::new(SCondvar::new()); let deleting = Arc::new(AtomicBool::new(false)); @@ -185,44 +222,82 @@ impl VerificationQueue { let empty = Arc::new(SCondvar::new()); let panic_handler = PanicHandler::new_in_arc(); - let mut verifiers: Vec> = Vec::new(); - let thread_count = max(::num_cpus::get(), 3) - 2; - for i in 0..thread_count { - let verification = verification.clone(); - let engine = engine.clone(); - let more_to_verify = more_to_verify.clone(); - let ready_signal = ready_signal.clone(); - let empty = empty.clone(); + let max_verifiers = min(::num_cpus::get(), MAX_VERIFIERS); + let default_amount = max(::num_cpus::get(), 3) - 2; + let mut verifiers = Vec::with_capacity(max_verifiers); + + debug!(target: "verification", "Allocating {} verifiers, {} initially active", max_verifiers, default_amount); + + for i in 0..max_verifiers { + debug!(target: "verification", "Adding verification thread #{}", i); + let deleting = deleting.clone(); let panic_handler = panic_handler.clone(); - verifiers.push( - thread::Builder::new() - .name(format!("Verifier #{}", i)) - .spawn(move || { - panic_handler.catch_panic(move || { - VerificationQueue::verify(verification, engine, more_to_verify, ready_signal, deleting, empty, check_seal) - }).unwrap() - }) - .expect("Error starting block verification thread") - ); + let verification = verification.clone(); + let engine = engine.clone(); + let wait = more_to_verify.clone(); + let ready = ready_signal.clone(); + let empty = empty.clone(); + + // enable only the first few verifiers. + let sleep = if i < default_amount { + Arc::new(AtomicBool::new(false)) + } else { + Arc::new(AtomicBool::new(true)) + }; + + verifiers.push(VerifierHandle { + deleting: deleting.clone(), + sleep: sleep.clone(), + thread: thread::Builder::new() + .name(format!("Verifier #{}", i)) + .spawn(move || { + panic_handler.catch_panic(move || { + VerificationQueue::verify(verification, engine, wait, ready, deleting, empty, sleep) + }).unwrap() + }) + .expect("Failed to create verifier thread.") + }); } + VerificationQueue { engine: engine, panic_handler: panic_handler, - ready_signal: ready_signal.clone(), - more_to_verify: more_to_verify.clone(), - verification: verification.clone(), - verifiers: verifiers, - deleting: deleting.clone(), + ready_signal: ready_signal, + more_to_verify: more_to_verify, + verification: verification, + verifiers: Mutex::new((verifiers, default_amount)), + deleting: deleting, processing: RwLock::new(HashSet::new()), - empty: empty.clone(), + empty: empty, + ticks_since_adjustment: AtomicUsize::new(0), max_queue_size: max(config.max_queue_size, MIN_QUEUE_LIMIT), max_mem_use: max(config.max_mem_use, MIN_MEM_LIMIT), } } - fn verify(verification: Arc>, engine: Arc, wait: Arc, ready: Arc, deleting: Arc, empty: Arc, check_seal: bool) { + fn verify( + verification: Arc>, + engine: Arc, + wait: Arc, + ready: Arc, + deleting: Arc, + empty: Arc, + sleep: Arc, + ) { while !deleting.load(AtomicOrdering::Acquire) { + { + while sleep.load(AtomicOrdering::SeqCst) { + trace!(target: "verification", "Verifier sleeping"); + ::std::thread::park(); + trace!(target: "verification", "Verifier waking up"); + + if deleting.load(AtomicOrdering::Acquire) { + return; + } + } + } + { let mut more_to_verify = verification.more_to_verify.lock().unwrap(); @@ -255,7 +330,7 @@ impl VerificationQueue { }; let hash = item.hash(); - let is_ready = match K::verify(item, &*engine, check_seal) { + let is_ready = match K::verify(item, &*engine, verification.check_seal) { Ok(verified) => { let mut verifying = verification.verifying.lock(); let mut idx = None; @@ -302,9 +377,15 @@ impl VerificationQueue { } } - fn drain_verifying(verifying: &mut VecDeque>, verified: &mut VecDeque, bad: &mut HashSet, sizes: &Sizes) { + fn drain_verifying( + verifying: &mut VecDeque>, + verified: &mut VecDeque, + bad: &mut HashSet, + sizes: &Sizes, + ) { let mut removed_size = 0; let mut inserted_size = 0; + while let Some(output) = verifying.front_mut().and_then(|x| x.output.take()) { assert!(verifying.pop_front().is_some()); let size = output.heap_size_of_children(); @@ -487,14 +568,85 @@ impl VerificationQueue { } } - /// Optimise memory footprint of the heap fields. + /// Optimise memory footprint of the heap fields, and adjust the number of threads + /// to better suit the workload. pub fn collect_garbage(&self) { - { - self.verification.unverified.lock().shrink_to_fit(); + // number of ticks to average queue stats over + // when deciding whether to change the number of verifiers. + #[cfg(not(test))] + const READJUSTMENT_PERIOD: usize = 12; + + #[cfg(test)] + const READJUSTMENT_PERIOD: usize = 1; + + let (u_len, v_len) = { + let u_len = { + let mut q = self.verification.unverified.lock(); + q.shrink_to_fit(); + q.len() + }; self.verification.verifying.lock().shrink_to_fit(); - self.verification.verified.lock().shrink_to_fit(); - } + + let v_len = { + let mut q = self.verification.verified.lock(); + q.shrink_to_fit(); + q.len() + }; + + (u_len as isize, v_len as isize) + }; + self.processing.write().shrink_to_fit(); + + if self.ticks_since_adjustment.fetch_add(1, AtomicOrdering::SeqCst) + 1 >= READJUSTMENT_PERIOD { + self.ticks_since_adjustment.store(0, AtomicOrdering::SeqCst); + } else { + return; + } + + let current = self.verifiers.lock().1; + + let diff = (v_len - u_len).abs(); + let total = v_len + u_len; + + self.scale_verifiers( + if u_len < 20 { + 1 + } else if diff <= total / 10 { + current + } else if v_len > u_len { + current - 1 + } else { + current + 1 + } + ); + } + + // wake up or sleep verifiers to get as close to the target as + // possible, never going over the amount of initially allocated threads + // or below 1. + fn scale_verifiers(&self, target: usize) { + let mut verifiers = self.verifiers.lock(); + let &mut (ref mut verifiers, ref mut verifier_count) = &mut *verifiers; + + let target = min(verifiers.len(), target); + let target = max(1, target); + + debug!(target: "verification", "Scaling from {} to {} verifiers", verifier_count, target); + + // scaling up + for i in *verifier_count..target { + debug!(target: "verification", "Waking up verifier {}", i); + verifiers[i].wake_up(); + } + + // scaling down. + for i in target..*verifier_count { + debug!(target: "verification", "Putting verifier {} to sleep", i); + verifiers[i].sleep(); + } + + *verifier_count = target; } } @@ -509,10 +661,23 @@ impl Drop for VerificationQueue { trace!(target: "shutdown", "[VerificationQueue] Closing..."); self.clear(); self.deleting.store(true, AtomicOrdering::Release); - self.more_to_verify.notify_all(); - for t in self.verifiers.drain(..) { - t.join().unwrap(); + + let mut verifiers = self.verifiers.get_mut(); + let mut verifiers = &mut verifiers.0; + + // first pass to signal conclusion. must be done before + // notify or deadlock possible. + for handle in verifiers.iter() { + handle.conclude(); } + + self.more_to_verify.notify_all(); + + // second pass to join. + for handle in verifiers.drain(..) { + handle.join(); + } + trace!(target: "shutdown", "[VerificationQueue] Closed."); } } @@ -611,4 +776,56 @@ mod tests { } assert!(queue.queue_info().is_full()); } + + #[test] + fn scaling_limits() { + use super::MAX_VERIFIERS; + + let queue = get_test_queue(); + queue.scale_verifiers(MAX_VERIFIERS + 1); + + assert!(queue.verifiers.lock().1 < MAX_VERIFIERS + 1); + + queue.scale_verifiers(0); + + assert!(queue.verifiers.lock().1 == 1); + } + + #[test] + fn readjust_verifiers() { + let queue = get_test_queue(); + + // put all the verifiers to sleep to ensure + // the test isn't timing sensitive. + let num_verifiers = { + let verifiers = queue.verifiers.lock(); + for i in 0..verifiers.1 { + verifiers.0[i].sleep(); + } + + verifiers.1 + }; + + for block in get_good_dummy_block_seq(5000) { + queue.import(Unverified::new(block)).expect("Block good by definition; qed"); + } + + // almost all unverified == bump verifier count. + queue.collect_garbage(); + assert_eq!(queue.verifiers.lock().1, num_verifiers + 1); + + // wake them up again and verify everything. + { + let verifiers = queue.verifiers.lock(); + for i in 0..verifiers.1 { + verifiers.0[i].wake_up(); + } + } + + queue.flush(); + + // nothing to verify == use minimum number of verifiers. + queue.collect_garbage(); + assert_eq!(queue.verifiers.lock().1, 1); + } } diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 47b2e16de..7e42e8881 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -29,6 +29,7 @@ use header::{BlockNumber, Header}; use rlp::{UntrustedRlp, View}; use transaction::SignedTransaction; use views::BlockView; +use time::get_time; /// Preprocessed block data gathered in `verify_block_unordered` call pub struct PreverifiedBlock { @@ -209,6 +210,10 @@ pub fn verify_header_params(header: &Header, engine: &Engine) -> Result<(), Erro if header.number() != 0 && header.extra_data().len() > maximum_extra_data_size { return Err(From::from(BlockError::ExtraDataOutOfBounds(OutOfBounds { min: None, max: Some(maximum_extra_data_size), found: header.extra_data().len() }))); } + let max_time = get_time().sec as u64 + 30; + if header.timestamp() > max_time { + return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: Some(max_time), min: None, found: header.timestamp() }))) + } Ok(()) } @@ -258,6 +263,7 @@ mod tests { use tests::helpers::*; use types::log_entry::{LogEntry, LocalizedLogEntry}; use rlp::View; + use time::get_time; fn check_ok(result: Result<(), Error>) { result.unwrap_or_else(|e| panic!("Block verification failed: {:?}", e)); @@ -271,6 +277,14 @@ mod tests { } } + fn check_fail_timestamp(result: Result<(), Error>) { + match result { + Err(Error::Block(BlockError::InvalidTimestamp(_))) => (), + Err(other) => panic!("Block verification failed.\nExpected: InvalidTimestamp\nGot: {:?}", other), + Ok(_) => panic!("Block verification failed.\nExpected: InvalidTimestamp\nGot: Ok"), + } + } + struct TestBlockChain { blocks: HashMap, numbers: HashMap, @@ -515,6 +529,14 @@ mod tests { check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc), InvalidTimestamp(OutOfBounds { max: None, min: Some(parent.timestamp() + 1), found: header.timestamp() })); + header = good.clone(); + header.set_timestamp(2450000000); + check_fail_timestamp(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine)); + + header = good.clone(); + header.set_timestamp(get_time().sec as u64 + 40); + check_fail_timestamp(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine)); + header = good.clone(); header.set_number(9); check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc), diff --git a/ethstore/src/random.rs b/ethstore/src/random.rs index 1d050e422..954ec500f 100644 --- a/ethstore/src/random.rs +++ b/ethstore/src/random.rs @@ -47,7 +47,7 @@ impl Random for [u8; 32] { pub fn random_phrase(words: usize) -> String { lazy_static! { static ref WORDS: Vec = String::from_utf8_lossy(include_bytes!("../res/wordlist.txt")) - .split("\n") + .lines() .map(|s| s.to_owned()) .collect(); } @@ -55,8 +55,19 @@ pub fn random_phrase(words: usize) -> String { (0..words).map(|_| rng.choose(&WORDS).unwrap()).join(" ") } -#[test] -fn should_produce_right_number_of_words() { - let p = random_phrase(10); - assert_eq!(p.split(" ").count(), 10); -} \ No newline at end of file +#[cfg(test)] +mod tests { + use super::random_phrase; + + #[test] + fn should_produce_right_number_of_words() { + let p = random_phrase(10); + assert_eq!(p.split(" ").count(), 10); + } + + #[test] + fn should_not_include_carriage_return() { + let p = random_phrase(10); + assert!(!p.contains('\r'), "Carriage return should be trimmed."); + } +} diff --git a/js/.babelrc b/js/.babelrc index 27c697885..2298d98c0 100644 --- a/js/.babelrc +++ b/js/.babelrc @@ -1,5 +1,8 @@ { - "presets": ["es2017", "es2016", "es2015", "stage-0", "react"], + "presets": [ + "es2017", "es2016", "es2015", + "stage-0", "react" + ], "plugins": [ "transform-runtime", "transform-decorators-legacy", @@ -10,6 +13,9 @@ "env": { "production": { "plugins": ["transform-react-remove-prop-types"] + }, + "development": { + "plugins": ["react-hot-loader/babel"] } } } diff --git a/js/.eslintrc.json b/js/.eslintrc.json index b649a1bea..198750580 100644 --- a/js/.eslintrc.json +++ b/js/.eslintrc.json @@ -15,6 +15,7 @@ "no-debugger": "error", "no-alert": "error", "jsx-quotes": ["error", "prefer-single"], - "react/jsx-curly-spacing": ["error", "always"] + "react/jsx-curly-spacing": ["error", "always"], + "object-property-newline": 0 } } diff --git a/js/.npmrc b/js/.npmrc new file mode 100644 index 000000000..3f7b4cf25 --- /dev/null +++ b/js/.npmrc @@ -0,0 +1 @@ +save-prefix='~' diff --git a/js/assets/images/certifications/unknown.svg b/js/assets/images/certifications/unknown.svg new file mode 100644 index 000000000..1554bcc25 --- /dev/null +++ b/js/assets/images/certifications/unknown.svg @@ -0,0 +1,4 @@ + + + + diff --git a/js/package.json b/js/package.json index 7f4157cad..420bc831e 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "0.2.58", + "version": "0.2.84", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", @@ -26,16 +26,16 @@ ], "scripts": { "build": "npm run build:lib && npm run build:dll && npm run build:app", - "build:app": "webpack --progress", - "build:lib": "webpack --config webpack.libraries --progress", - "build:dll": "webpack --config webpack.vendor --progress", + "build:app": "webpack --config webpack/app --progress", + "build:lib": "webpack --config webpack/libraries --progress", + "build:dll": "webpack --config webpack/vendor --progress", "ci:build": "npm run ci:build:lib && npm run ci:build:dll && npm run ci:build:app", - "ci:build:app": "NODE_ENV=production webpack", - "ci:build:lib": "NODE_ENV=production webpack --config webpack.libraries", - "ci:build:dll": "NODE_ENV=production webpack --config webpack.vendor", - "ci:build:npm": "NODE_ENV=production webpack --config webpack.npm", + "ci:build:app": "NODE_ENV=production webpack --config webpack/app", + "ci:build:lib": "NODE_ENV=production webpack --config webpack/libraries", + "ci:build:dll": "NODE_ENV=production webpack --config webpack/vendor", + "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:app": "webpack-dev-server -d --history-api-fallback --open --hot --inline --progress --colors --port 3000", + "start:app": "node webpack/dev.server", "clean": "rm -rf ./build ./coverage", "coveralls": "npm run testCoverage && coveralls < coverage/lcov.info", "lint": "eslint --ignore-path .gitignore ./src/", @@ -47,126 +47,133 @@ "prepush": "npm run lint:cached" }, "devDependencies": { - "babel-cli": "^6.10.1", - "babel-core": "^6.10.4", - "babel-eslint": "^7.1.0", - "babel-loader": "^6.2.3", - "babel-plugin-lodash": "^3.2.2", - "babel-plugin-transform-class-properties": "^6.11.5", - "babel-plugin-transform-decorators-legacy": "^1.3.4", - "babel-plugin-transform-react-remove-prop-types": "^0.2.9", - "babel-plugin-transform-runtime": "^6.9.0", - "babel-polyfill": "^6.13.0", - "babel-preset-es2015": "^6.9.0", - "babel-preset-es2015-rollup": "^1.1.1", - "babel-preset-es2016": "^6.11.3", - "babel-preset-es2017": "^6.14.0", - "babel-preset-react": "^6.5.0", - "babel-preset-stage-0": "^6.5.0", - "babel-register": "6.9.0", - "babel-runtime": "^6.9.2", - "chai": "^3.5.0", + "babel-cli": "~6.18.0", + "babel-core": "~6.18.2", + "babel-eslint": "~7.1.0", + "babel-loader": "~6.2.3", + "babel-plugin-lodash": "~3.2.2", + "babel-plugin-transform-class-properties": "~6.19.0", + "babel-plugin-transform-decorators-legacy": "~1.3.4", + "babel-plugin-transform-react-remove-prop-types": "~0.2.9", + "babel-plugin-transform-runtime": "~6.15.0", + "babel-polyfill": "~6.16.0", + "babel-preset-es2015": "~6.18.0", + "babel-preset-es2015-rollup": "~1.2.0", + "babel-preset-es2016": "~6.16.0", + "babel-preset-es2017": "~6.16.0", + "babel-preset-react": "~6.16.0", + "babel-preset-stage-0": "~6.16.0", + "babel-register": "6.18.0", + "babel-runtime": "~6.18.0", + "chai": "~3.5.0", "chai-enzyme": "0.4.2", "cheerio": "0.20.0", - "copy-webpack-plugin": "^4.0.0", - "core-js": "^2.4.1", - "coveralls": "^2.11.11", - "css-loader": "^0.23.1", + "copy-webpack-plugin": "~4.0.0", + "core-js": "~2.4.1", + "coveralls": "~2.11.11", + "css-loader": "~0.26.0", + "ejs-loader": "~0.3.0", "enzyme": "2.3.0", - "eslint": "^3.1.0", - "eslint-config-semistandard": "^6.0.2", - "eslint-config-standard": "^5.3.5", - "eslint-config-standard-react": "^3.0.0", - "eslint-plugin-promise": "^2.0.0", - "eslint-plugin-react": "^5.1.1", - "eslint-plugin-standard": "^2.0.0", - "extract-loader": "0.0.2", - "extract-text-webpack-plugin": "^1.0.1", - "file-loader": "^0.8.5", - "fs-extra": "^0.30.0", - "happypack": "^2.2.1", - "history": "^2.0.0", - "html-loader": "^0.4.4", - "husky": "^0.11.9", + "eslint": "~3.10.2", + "eslint-config-semistandard": "~7.0.0", + "eslint-config-standard": "~6.2.1", + "eslint-config-standard-react": "~4.2.0", + "eslint-plugin-promise": "~3.4.0", + "eslint-plugin-react": "~6.7.1", + "eslint-plugin-standard": "~2.0.0", + "express": "~4.14.0", + "extract-loader": "0.1.0", + "extract-text-webpack-plugin": "~2.0.0-beta.4", + "file-loader": "~0.9.0", + "fs-extra": "~0.30.0", + "happypack": "~3.0.0", + "history": "~2.0.0", + "html-loader": "~0.4.4", + "html-webpack-plugin": "~2.24.1", + "http-proxy-middleware": "~0.17.2", + "husky": "~0.11.9", "ignore-styles": "2.0.0", - "image-webpack-loader": "^1.8.0", - "istanbul": "^1.0.0-alpha.2", + "image-webpack-loader": "~3.0.0", + "istanbul": "~1.0.0-alpha.2", "jsdom": "9.2.1", - "json-loader": "^0.5.4", - "mocha": "^3.0.0-1", + "json-loader": "~0.5.4", + "mocha": "~3.0.0-1", "mock-local-storage": "1.0.2", - "mock-socket": "^3.0.1", - "nock": "^8.0.0", - "postcss-import": "^8.1.2", - "postcss-loader": "^0.8.1", - "postcss-nested": "^1.0.0", - "postcss-simple-vars": "^3.0.0", - "raw-loader": "^0.5.1", + "mock-socket": "~3.0.1", + "nock": "~8.0.0", + "postcss-import": "8.1.0", + "postcss-loader": "~1.1.1", + "postcss-nested": "~1.0.0", + "postcss-simple-vars": "~3.0.0", + "progress": "~1.1.8", + "raw-loader": "~0.5.1", + "react-addons-perf": "~15.3.2", "react-addons-test-utils": "~15.3.2", - "react-copy-to-clipboard": "^4.2.3", "react-dom": "~15.3.2", - "react-hot-loader": "~1.3.0", - "rucksack-css": "^0.8.6", - "sinon": "^1.17.4", - "sinon-as-promised": "^4.0.2", - "sinon-chai": "^2.8.0", - "style-loader": "^0.13.0", - "url-loader": "^0.5.7", - "webpack": "^1.13.2", - "webpack-dev-server": "^1.15.2", + "react-hot-loader": "~3.0.0-beta.6", + "rucksack-css": "~0.8.6", + "sinon": "~1.17.4", + "sinon-as-promised": "~4.0.2", + "sinon-chai": "~2.8.0", + "style-loader": "~0.13.0", + "url-loader": "~0.5.7", + "webpack": "~2.1.0-beta.27", + "webpack-dev-middleware": "~1.8.4", "webpack-error-notification": "0.1.6", "webpack-hot-middleware": "~2.13.2", - "websocket": "^1.0.23" + "websocket": "~1.0.23" }, "dependencies": { - "bignumber.js": "^2.3.0", + "bignumber.js": "~2.3.0", "blockies": "0.0.2", - "brace": "^0.9.0", - "bytes": "^2.4.0", - "chart.js": "^2.3.0", - "es6-error": "^4.0.0", - "es6-promise": "^3.2.1", - "ethereumjs-tx": "^1.1.2", - "file-saver": "^1.3.3", - "format-json": "^1.0.3", - "format-number": "^2.0.1", - "geopattern": "^1.2.3", - "isomorphic-fetch": "^2.2.1", - "js-sha3": "^0.5.2", - "lodash": "^4.11.1", - "marked": "^0.3.6", + "brace": "~0.9.0", + "bytes": "~2.4.0", + "chart.js": "~2.3.0", + "es6-error": "~4.0.0", + "es6-promise": "~3.2.1", + "ethereumjs-tx": "~1.1.2", + "eventemitter3": "~2.0.2", + "file-saver": "~1.3.3", + "format-json": "~1.0.3", + "format-number": "~2.0.1", + "geopattern": "~1.2.3", + "isomorphic-fetch": "~2.2.1", + "js-sha3": "~0.5.2", + "lodash": "~4.11.1", + "marked": "~0.3.6", "material-ui": "0.16.1", - "material-ui-chip-input": "^0.8.0", - "mobx": "^2.6.1", - "mobx-react": "^3.5.8", - "mobx-react-devtools": "^4.2.9", - "moment": "^2.14.1", - "phoneformat.js": "^1.0.3", - "qs": "^6.3.0", + "material-ui-chip-input": "~0.8.0", + "mobx": "~2.6.1", + "mobx-react": "~3.5.8", + "mobx-react-devtools": "~4.2.9", + "moment": "~2.14.1", + "phoneformat.js": "~1.0.3", + "qs": "~6.3.0", "react": "~15.3.2", - "react-ace": "^4.0.0", + "react-ace": "~4.0.0", "react-addons-css-transition-group": "~15.3.2", - "react-chartjs-2": "^1.5.0", + "react-chartjs-2": "~1.5.0", + "react-copy-to-clipboard": "~4.2.3", "react-dom": "~15.3.2", - "react-dropzone": "^3.7.3", - "react-redux": "^4.4.5", - "react-router": "^2.6.1", - "react-router-redux": "^4.0.5", + "react-dropzone": "~3.7.3", + "react-redux": "~4.4.5", + "react-router": "~2.6.1", + "react-router-redux": "~4.0.5", "react-tap-event-plugin": "~1.0.0", - "react-tooltip": "^2.0.3", - "recharts": "^0.15.2", - "redux": "^3.5.2", - "redux-actions": "^0.10.1", - "redux-thunk": "^2.1.0", - "rlp": "^2.0.0", - "scryptsy": "^2.0.0", + "react-tooltip": "~2.0.3", + "recharts": "~0.15.2", + "redux": "~3.5.2", + "redux-actions": "~0.10.1", + "redux-thunk": "~2.1.0", + "rlp": "~2.0.0", + "scryptsy": "~2.0.0", "solc": "ngotchac/solc-js", - "store": "^1.3.20", - "utf8": "^2.1.1", - "valid-url": "^1.0.9", - "validator": "^5.7.0", - "web3": "^0.17.0-beta", - "whatwg-fetch": "^1.0.0", - "worker-loader": "^0.7.1" + "store": "~1.3.20", + "utf8": "~2.1.1", + "valid-url": "~1.0.9", + "validator": "~5.7.0", + "web3": "~0.17.0-beta", + "whatwg-fetch": "~1.0.0", + "worker-loader": "~0.7.1" } } diff --git a/js/src/3rdparty/shapeshift/shapeshift.js b/js/src/3rdparty/shapeshift/shapeshift.js index 344a44802..8f388d0a7 100644 --- a/js/src/3rdparty/shapeshift/shapeshift.js +++ b/js/src/3rdparty/shapeshift/shapeshift.js @@ -15,7 +15,8 @@ // along with Parity. If not, see . export default function (rpc) { - const subscriptions = []; + let subscriptions = []; + let pollStatusIntervalId = null; function getCoins () { return rpc.get('getcoins'); @@ -45,6 +46,24 @@ export default function (rpc) { callback, idx }); + + // Only poll if there are subscriptions... + if (!pollStatusIntervalId) { + pollStatusIntervalId = setInterval(_pollStatus, 2000); + } + } + + function unsubscribe (depositAddress) { + const newSubscriptions = [] + .concat(subscriptions) + .filter((sub) => sub.depositAddress !== depositAddress); + + subscriptions = newSubscriptions; + + if (subscriptions.length === 0) { + clearInterval(pollStatusIntervalId); + pollStatusIntervalId = null; + } } function _getSubscriptionStatus (subscription) { @@ -81,13 +100,12 @@ export default function (rpc) { subscriptions.forEach(_getSubscriptionStatus); } - setInterval(_pollStatus, 2000); - return { getCoins, getMarketInfo, getStatus, shift, - subscribe + subscribe, + unsubscribe }; } diff --git a/js/src/modals/SMSVerification/terms-of-service.js b/js/src/3rdparty/sms-verification/index.js similarity index 79% rename from js/src/modals/SMSVerification/terms-of-service.js rename to js/src/3rdparty/sms-verification/index.js index f61b3c97d..c50b2331a 100644 --- a/js/src/modals/SMSVerification/terms-of-service.js +++ b/js/src/3rdparty/sms-verification/index.js @@ -14,9 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +import { stringify } from 'querystring'; import React from 'react'; -export default ( +export const termsOfService = (
  • This privacy notice relates to your use of the Parity SMS verification service. We take your privacy seriously and deal in an honest, direct and transparent way when it comes to your data.
  • We collect your phone number when you use this service. This is temporarily kept in memory, and then encrypted and stored in our EU servers. We only retain the cryptographic hash of the number to prevent duplicated accounts. You consent to this use.
  • @@ -25,3 +26,19 @@ export default (
  • Parity Technology Limited is registered in England and Wales under company number 09760015 and complies with the Data Protection Act 1998 (UK). You may contact us via email at admin@parity.io. Our general privacy policy can be found here: https://ethcore.io/legal.html.
); + +export const postToServer = (query, isTestnet = false) => { + const port = isTestnet ? 8443 : 443; + query = stringify(query); + return fetch(`https://sms-verification.parity.io:${port}/?` + query, { + method: 'POST', mode: 'cors', cache: 'no-store' + }) + .then((res) => { + return res.json().then((data) => { + if (res.ok) { + return data.message; + } + throw new Error(data.message || 'unknown error'); + }); + }); +}; diff --git a/js/src/api/contract/contract.js b/js/src/api/contract/contract.js index 06afb0d9d..c1ba8498d 100644 --- a/js/src/api/contract/contract.js +++ b/js/src/api/contract/contract.js @@ -15,16 +15,16 @@ // along with Parity. If not, see . import Abi from '../../abi'; -import Api from '../api'; -import { isInstanceOf } from '../util/types'; let nextSubscriptionId = 0; export default class Contract { constructor (api, abi) { - if (!isInstanceOf(api, Api)) { + if (!api) { throw new Error('API instance needs to be provided to Contract'); - } else if (!abi) { + } + + if (!abi) { throw new Error('ABI needs to be provided to Contract instance'); } @@ -48,7 +48,11 @@ export default class Contract { this._instance[fn.signature] = fn; }); - this._sendSubscriptionChanges(); + this._subscribedToPendings = false; + this._pendingsSubscriptionId = null; + + this._subscribedToBlock = false; + this._blockSubscriptionId = null; } get address () { @@ -239,44 +243,71 @@ export default class Contract { return event; } - subscribe (eventName = null, options = {}, callback) { - return new Promise((resolve, reject) => { - let event = null; + _findEvent (eventName = null) { + const event = eventName + ? this._events.find((evt) => evt.name === eventName) + : null; - if (eventName) { - event = this._events.find((evt) => evt.name === eventName); + if (eventName && !event) { + const events = this._events.map((evt) => evt.name).join(', '); + throw new Error(`${eventName} is not a valid eventName, subscribe using one of ${events} (or null to include all)`); + } - if (!event) { - const events = this._events.map((evt) => evt.name).join(', '); - reject(new Error(`${eventName} is not a valid eventName, subscribe using one of ${events} (or null to include all)`)); - return; - } - } + return event; + } - return this._subscribe(event, options, callback).then(resolve).catch(reject); + _createEthFilter (event = null, _options) { + const optionTopics = _options.topics || []; + const signature = event && event.signature || null; + + // If event provided, remove the potential event signature + // as the first element of the topics + const topics = signature + ? [ signature ].concat(optionTopics.filter((t, idx) => idx > 0 || t !== signature)) + : optionTopics; + + const options = Object.assign({}, _options, { + address: this._address, + topics }); + + return this._api.eth.newFilter(options); + } + + subscribe (eventName = null, options = {}, callback) { + try { + const event = this._findEvent(eventName); + return this._subscribe(event, options, callback); + } catch (e) { + return Promise.reject(e); + } } _subscribe (event = null, _options, callback) { const subscriptionId = nextSubscriptionId++; - const options = Object.assign({}, _options, { - address: this._address, - topics: [event ? event.signature : null] - }); + const { skipInitFetch } = _options; + delete _options['skipInitFetch']; - return this._api.eth - .newFilter(options) + return this + ._createEthFilter(event, _options) .then((filterId) => { + this._subscriptions[subscriptionId] = { + options: _options, + callback, + filterId + }; + + if (skipInitFetch) { + this._subscribeToChanges(); + return subscriptionId; + } + return this._api.eth .getFilterLogs(filterId) .then((logs) => { callback(null, this.parseEventLogs(logs)); - this._subscriptions[subscriptionId] = { - options, - callback, - filterId - }; + this._subscribeToChanges(); return subscriptionId; }); }); @@ -285,19 +316,89 @@ export default class Contract { unsubscribe (subscriptionId) { return this._api.eth .uninstallFilter(this._subscriptions[subscriptionId].filterId) - .then(() => { - delete this._subscriptions[subscriptionId]; - }) .catch((error) => { console.error('unsubscribe', error); + }) + .then(() => { + delete this._subscriptions[subscriptionId]; + this._unsubscribeFromChanges(); }); } - _sendSubscriptionChanges = () => { + _subscribeToChanges = () => { const subscriptions = Object.values(this._subscriptions); - const timeout = () => setTimeout(this._sendSubscriptionChanges, 1000); - Promise + const pendingSubscriptions = subscriptions + .filter((s) => s.options.toBlock && s.options.toBlock === 'pending'); + + const otherSubscriptions = subscriptions + .filter((s) => !(s.options.toBlock && s.options.toBlock === 'pending')); + + if (pendingSubscriptions.length > 0 && !this._subscribedToPendings) { + this._subscribedToPendings = true; + this._subscribeToPendings(); + } + + if (otherSubscriptions.length > 0 && !this._subscribedToBlock) { + this._subscribedToBlock = true; + this._subscribeToBlock(); + } + } + + _unsubscribeFromChanges = () => { + const subscriptions = Object.values(this._subscriptions); + + const pendingSubscriptions = subscriptions + .filter((s) => s.options.toBlock && s.options.toBlock === 'pending'); + + const otherSubscriptions = subscriptions + .filter((s) => !(s.options.toBlock && s.options.toBlock === 'pending')); + + if (pendingSubscriptions.length === 0 && this._subscribedToPendings) { + this._subscribedToPendings = false; + clearTimeout(this._pendingsSubscriptionId); + } + + if (otherSubscriptions.length === 0 && this._subscribedToBlock) { + this._subscribedToBlock = false; + this._api.unsubscribe(this._blockSubscriptionId); + } + } + + _subscribeToBlock = () => { + this._api + .subscribe('eth_blockNumber', (error) => { + if (error) { + console.error('::_subscribeToBlock', error, error && error.stack); + } + + const subscriptions = Object.values(this._subscriptions) + .filter((s) => !(s.options.toBlock && s.options.toBlock === 'pending')); + + this._sendSubscriptionChanges(subscriptions); + }) + .then((blockSubId) => { + this._blockSubscriptionId = blockSubId; + }) + .catch((e) => { + console.error('::_subscribeToBlock', e, e && e.stack); + }); + } + + _subscribeToPendings = () => { + const subscriptions = Object.values(this._subscriptions) + .filter((s) => s.options.toBlock && s.options.toBlock === 'pending'); + + const timeout = () => setTimeout(() => this._subscribeToPendings(), 1000); + + this._sendSubscriptionChanges(subscriptions) + .then(() => { + this._pendingsSubscriptionId = timeout(); + }); + } + + _sendSubscriptionChanges = (subscriptions) => { + return Promise .all( subscriptions.map((subscription) => { return this._api.eth.getFilterChanges(subscription.filterId); @@ -315,12 +416,9 @@ export default class Contract { console.error('_sendSubscriptionChanges', error); } }); - - timeout(); }) .catch((error) => { console.error('_sendSubscriptionChanges', error); - timeout(); }); } } diff --git a/js/src/api/contract/contract.spec.js b/js/src/api/contract/contract.spec.js index 9c08024a9..970dd606d 100644 --- a/js/src/api/contract/contract.spec.js +++ b/js/src/api/contract/contract.spec.js @@ -437,6 +437,7 @@ describe('api/contract/Contract', () => { ] } ]; + const logs = [{ address: '0x22bff18ec62281850546a664bb63a5c06ac5f76c', blockHash: '0xa9280530a3b47bee2fc80f2862fd56502ae075350571d724d6442ea4c597347b', @@ -450,6 +451,7 @@ describe('api/contract/Contract', () => { transactionHash: '0xca16f537d761d13e4e80953b754e2b15541f267d6cad9381f750af1bae1e4917', transactionIndex: '0x0' }]; + const parsed = [{ address: '0x22bfF18ec62281850546a664bb63a5C06AC5F76C', blockHash: '0xa9280530a3b47bee2fc80f2862fd56502ae075350571d724d6442ea4c597347b', @@ -466,11 +468,13 @@ describe('api/contract/Contract', () => { sender: { type: 'address', value: '0x63Cf90D3f0410092FC0fca41846f596223979195' } }, topics: [ - '0x954ba6c157daf8a26539574ffa64203c044691aa57251af95f4b48d85ec00dd5', '0x0000000000000000000000000000000000000000000000000001000000004fe0' + '0x954ba6c157daf8a26539574ffa64203c044691aa57251af95f4b48d85ec00dd5', + '0x0000000000000000000000000000000000000000000000000001000000004fe0' ], transactionHash: '0xca16f537d761d13e4e80953b754e2b15541f267d6cad9381f750af1bae1e4917', transactionIndex: new BigNumber(0) }]; + let contract; beforeEach(() => { @@ -496,18 +500,19 @@ describe('api/contract/Contract', () => { scope = mockHttp([ { method: 'eth_newFilter', reply: { result: '0x123' } }, { method: 'eth_getFilterLogs', reply: { result: logs } }, + { method: 'eth_getFilterChanges', reply: { result: logs } }, { method: 'eth_newFilter', reply: { result: '0x123' } }, { method: 'eth_getFilterLogs', reply: { result: logs } } ]); cbb = sinon.stub(); cbe = sinon.stub(); - return contract.subscribe('Message', {}, cbb); + return contract.subscribe('Message', { toBlock: 'pending' }, cbb); }); it('sets the subscriptionId returned', () => { return contract - .subscribe('Message', {}, cbe) + .subscribe('Message', { toBlock: 'pending' }, cbe) .then((subscriptionId) => { expect(subscriptionId).to.equal(1); }); @@ -515,7 +520,7 @@ describe('api/contract/Contract', () => { it('creates a new filter and retrieves the logs on it', () => { return contract - .subscribe('Message', {}, cbe) + .subscribe('Message', { toBlock: 'pending' }, cbe) .then((subscriptionId) => { expect(scope.isDone()).to.be.true; }); @@ -523,7 +528,7 @@ describe('api/contract/Contract', () => { it('returns the logs to the callback', () => { return contract - .subscribe('Message', {}, cbe) + .subscribe('Message', { toBlock: 'pending' }, cbe) .then((subscriptionId) => { expect(cbe).to.have.been.calledWith(null, parsed); }); diff --git a/js/src/api/format/input.js b/js/src/api/format/input.js index 4cd1c8a56..6d261c674 100644 --- a/js/src/api/format/input.js +++ b/js/src/api/format/input.js @@ -17,6 +17,7 @@ import BigNumber from 'bignumber.js'; import { isArray, isHex, isInstanceOf, isString } from '../util/types'; +import { padLeft, toHex } from '../util/format'; export function inAddress (address) { // TODO: address validation if we have upper-lower addresses @@ -52,12 +53,18 @@ export function inHash (hash) { export function inTopics (_topics) { let topics = (_topics || []) - .filter((topic) => topic) - .map(inHex); + .filter((topic) => topic === null || topic) + .map((topic) => { + if (topic === null) { + return null; + } - while (topics.length < 4) { - topics.push(null); - } + if (Array.isArray(topic)) { + return inTopics(topic); + } + + return padLeft(topic, 32); + }); return topics; } @@ -93,15 +100,7 @@ export function inFilter (options) { } export function inHex (str) { - if (str && str.toString) { - str = str.toString(16); - } - - if (str && str.substr(0, 2) === '0x') { - return str.toLowerCase(); - } - - return `0x${(str || '').toLowerCase()}`; + return toHex(str); } export function inNumber10 (number) { diff --git a/js/src/api/format/output.js b/js/src/api/format/output.js index 262a275a0..1094cdb83 100644 --- a/js/src/api/format/output.js +++ b/js/src/api/format/output.js @@ -144,7 +144,8 @@ export function outSignerRequest (request) { break; case 'payload': - request[key].transaction = outTransaction(request[key].transaction); + request[key].signTransaction = outTransaction(request[key].signTransaction); + request[key].sendTransaction = outTransaction(request[key].sendTransaction); break; } }); diff --git a/js/src/api/rpc/parity/parity.js b/js/src/api/rpc/parity/parity.js index d14cc6554..ac16eb9b0 100644 --- a/js/src/api/rpc/parity/parity.js +++ b/js/src/api/rpc/parity/parity.js @@ -123,6 +123,11 @@ export default class Parity { .then((accounts) => (accounts || []).map(outAddress)); } + killAccount (account, password) { + return this._transport + .execute('parity_killAccount', inAddress(account), password); + } + listGethAccounts () { return this._transport .execute('parity_listGethAccounts') diff --git a/js/src/api/subscriptions/personal.js b/js/src/api/subscriptions/personal.js index 58428895b..2cb0c3ea0 100644 --- a/js/src/api/subscriptions/personal.js +++ b/js/src/api/subscriptions/personal.js @@ -59,6 +59,7 @@ export default class Personal { } switch (data.method) { + case 'parity_killAccount': case 'parity_importGethAccounts': case 'personal_newAccount': case 'parity_newAccountFromPhrase': diff --git a/js/src/api/transport/error.js b/js/src/api/transport/error.js index 341839f69..6cb0dac17 100644 --- a/js/src/api/transport/error.js +++ b/js/src/api/transport/error.js @@ -36,7 +36,8 @@ export const ERROR_CODES = { REQUEST_NOT_FOUND: -32042, COMPILATION_ERROR: -32050, ENCRYPTION_ERROR: -32055, - FETCH_ERROR: -32060 + FETCH_ERROR: -32060, + INVALID_PARAMS: -32602 }; export default class TransportError extends ExtendableError { diff --git a/js/src/api/transport/ws/ws.js b/js/src/api/transport/ws/ws.js index 7b214fded..53600b6d3 100644 --- a/js/src/api/transport/ws/ws.js +++ b/js/src/api/transport/ws/ws.js @@ -29,21 +29,33 @@ export default class Ws extends JsonRpcBase { this._token = token; this._messages = {}; - this._connecting = true; + this._connecting = false; + this._connected = false; this._lastError = null; - this._autoConnect = false; + this._autoConnect = true; + this._retries = 0; + this._reconnectTimeoutId = null; this._connect(); } updateToken (token) { this._token = token; - this._autoConnect = false; + this._autoConnect = true; this._connect(); } _connect () { + if (this._connecting) { + return; + } + + if (this._reconnectTimeoutId) { + window.clearTimeout(this._reconnectTimeoutId); + this._reconnectTimeoutId = null; + } + const time = parseInt(new Date().getTime() / 1000, 10); const sha3 = keccak_256(`${this._token}:${time}`); const hash = `${sha3}_${time}`; @@ -53,6 +65,7 @@ export default class Ws extends JsonRpcBase { this._ws.onopen = null; this._ws.onclose = null; this._ws.onmessage = null; + this._ws.close(); this._ws = null; } @@ -65,6 +78,32 @@ export default class Ws extends JsonRpcBase { this._ws.onopen = this._onOpen; this._ws.onclose = this._onClose; this._ws.onmessage = this._onMessage; + + // Get counts in dev mode only + if (process.env.NODE_ENV === 'development') { + this._count = 0; + this._lastCount = { + timestamp: Date.now(), + count: 0 + }; + + window.setInterval(() => { + const n = this._count - this._lastCount.count; + const t = (Date.now() - this._lastCount.timestamp) / 1000; + const s = Math.round(1000 * n / t) / 1000; + + if (this._debug) { + console.log('::parityWS', `speed: ${s} req/s`, `count: ${this._count}`, `(+${n})`); + } + + this._lastCount = { + timestamp: Date.now(), + count: this._count + }; + }, 5000); + + window._parityWS = this; + } } _onOpen = (event) => { @@ -72,6 +111,7 @@ export default class Ws extends JsonRpcBase { this._connected = true; this._connecting = false; this._autoConnect = true; + this._retries = 0; Object.keys(this._messages) .filter((id) => this._messages[id].queued) @@ -79,18 +119,42 @@ export default class Ws extends JsonRpcBase { } _onClose = (event) => { - console.log('ws:onClose', event); this._connected = false; this._connecting = false; + event.timestamp = Date.now(); + this._lastError = event; + if (this._autoConnect) { - setTimeout(() => this._connect(), 500); + const timeout = this.retryTimeout; + + const time = timeout < 1000 + ? Math.round(timeout) + 'ms' + : (Math.round(timeout / 10) / 100) + 's'; + + console.log('ws:onClose', `trying again in ${time}...`); + + this._reconnectTimeoutId = setTimeout(() => { + this._connect(); + }, timeout); + + return; } + + console.log('ws:onClose', event); } _onError = (event) => { - console.error('ws:onError', event); - this._lastError = event; + // Only print error if the WS is connected + // ie. don't print if error == closed + window.setTimeout(() => { + if (this._connected) { + console.error('ws:onError', event); + + event.timestamp = Date.now(); + this._lastError = event; + } + }, 50); } _onMessage = (event) => { @@ -127,11 +191,16 @@ export default class Ws extends JsonRpcBase { _send = (id) => { const message = this._messages[id]; - message.queued = !this._connected; - if (this._connected) { - this._ws.send(message.json); + if (process.env.NODE_ENV === 'development') { + this._count++; + } + + return this._ws.send(message.json); } + + message.queued = !this._connected; + message.timestamp = Date.now(); } execute (method, ...params) { @@ -159,4 +228,27 @@ export default class Ws extends JsonRpcBase { get lastError () { return this._lastError; } + + /** + * Exponential Timeout for Retries + * + * @see http://dthain.blogspot.de/2009/02/exponential-backoff-in-distributed.html + */ + get retryTimeout () { + // R between 1 and 2 + const R = Math.random() + 1; + // Initial timeout (100ms) + const T = 100; + // Exponential Factor + const F = 2; + // Max timeout (4s) + const M = 4000; + // Current number of retries + const N = this._retries; + + // Increase retries number + this._retries++; + + return Math.min(R * T * Math.pow(F, N), M); + } } diff --git a/js/src/api/util/format.js b/js/src/api/util/format.js index 198e456ee..7f60357cd 100644 --- a/js/src/api/util/format.js +++ b/js/src/api/util/format.js @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +import { range } from 'lodash'; + export function bytesToHex (bytes) { return '0x' + bytes.map((b) => ('0' + b.toString(16)).slice(-2)).join(''); } @@ -29,3 +31,29 @@ export function hex2Ascii (_hex) { return str; } + +export function asciiToHex (string) { + return '0x' + string.split('').map((s) => s.charCodeAt(0).toString(16)).join(''); +} + +export function padRight (input, length) { + const value = toHex(input).substr(2, length * 2); + return '0x' + value + range(length * 2 - value.length).map(() => '0').join(''); +} + +export function padLeft (input, length) { + const value = toHex(input).substr(2, length * 2); + return '0x' + range(length * 2 - value.length).map(() => '0').join('') + value; +} + +export function toHex (str) { + if (str && str.toString) { + str = str.toString(16); + } + + if (str && str.substr(0, 2) === '0x') { + return str.toLowerCase(); + } + + return `0x${(str || '').toLowerCase()}`; +} diff --git a/js/src/api/util/index.js b/js/src/api/util/index.js index 55cf008c5..2058cd011 100644 --- a/js/src/api/util/index.js +++ b/js/src/api/util/index.js @@ -16,7 +16,7 @@ import { isAddress as isAddressValid, toChecksumAddress } from '../../abi/util/address'; import { decodeCallData, decodeMethodInput, methodToAbi } from './decode'; -import { bytesToHex, hex2Ascii } from './format'; +import { bytesToHex, hex2Ascii, asciiToHex } from './format'; import { fromWei, toWei } from './wei'; import { sha3 } from './sha3'; import { isArray, isFunction, isHex, isInstanceOf, isString } from './types'; @@ -31,6 +31,7 @@ export default { isString, bytesToHex, hex2Ascii, + asciiToHex, createIdentityImg, decodeCallData, decodeMethodInput, diff --git a/js/src/contracts/abi/badgereg.json b/js/src/contracts/abi/badgereg.json new file mode 100644 index 000000000..3d18ba393 --- /dev/null +++ b/js/src/contracts/abi/badgereg.json @@ -0,0 +1 @@ +[{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_addr","type":"address"},{"name":"_name","type":"bytes32"}],"name":"register","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"fromName","outputs":[{"name":"id","type":"uint256"},{"name":"addr","type":"address"},{"name":"owner","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"badgeCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_fee","type":"uint256"}],"name":"setFee","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_id","type":"uint256"},{"name":"_key","type":"bytes32"}],"name":"meta","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"drain","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_id","type":"uint256"}],"name":"unregister","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_addr","type":"address"}],"name":"fromAddress","outputs":[{"name":"id","type":"uint256"},{"name":"name","type":"bytes32"},{"name":"owner","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_id","type":"uint256"}],"name":"badge","outputs":[{"name":"addr","type":"address"},{"name":"name","type":"bytes32"},{"name":"owner","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_id","type":"uint256"},{"name":"_key","type":"bytes32"},{"name":"_value","type":"bytes32"}],"name":"setMeta","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_addr","type":"address"},{"name":"_name","type":"bytes32"},{"name":"_owner","type":"address"}],"name":"registerAs","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"fee","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"id","type":"uint256"},{"indexed":false,"name":"addr","type":"address"}],"name":"Registered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"id","type":"uint256"}],"name":"Unregistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"id","type":"uint256"},{"indexed":true,"name":"key","type":"bytes32"},{"indexed":false,"name":"value","type":"bytes32"}],"name":"MetaChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"old","type":"address"},{"indexed":true,"name":"current","type":"address"}],"name":"NewOwner","type":"event"}] \ No newline at end of file diff --git a/js/src/contracts/abi/certifier.json b/js/src/contracts/abi/certifier.json new file mode 100644 index 000000000..905ddde6c --- /dev/null +++ b/js/src/contracts/abi/certifier.json @@ -0,0 +1 @@ +[{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"certified","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Confirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Revoked","type":"event"}] \ No newline at end of file diff --git a/js/src/contracts/abi/index.js b/js/src/contracts/abi/index.js index a6a7f0783..f15765b1a 100644 --- a/js/src/contracts/abi/index.js +++ b/js/src/contracts/abi/index.js @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +import badgereg from './badgereg.json'; import basiccoin from './basiccoin.json'; import basiccoinmanager from './basiccoinmanager.json'; import dappreg from './dappreg.json'; @@ -28,6 +29,7 @@ import tokenreg from './tokenreg.json'; import wallet from './wallet.json'; export { + badgereg, basiccoin, basiccoinmanager, dappreg, diff --git a/js/src/contracts/abi/sms-verification.json b/js/src/contracts/abi/sms-verification.json index 400d22b44..d6852b182 100644 --- a/js/src/contracts/abi/sms-verification.json +++ b/js/src/contracts/abi/sms-verification.json @@ -1 +1 @@ -[{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"certify","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"request","outputs":[],"payable":true,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"},{"name":"_puzzle","type":"bytes32"}],"name":"puzzle","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"uint256"}],"name":"setFee","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"revoke","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_code","type":"bytes32"}],"name":"confirm","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"drain","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"delegate","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setDelegate","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"certified","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"fee","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Requested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"},{"indexed":false,"name":"puzzle","type":"bytes32"}],"name":"Puzzled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Confirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Revoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"old","type":"address"},{"indexed":true,"name":"current","type":"address"}],"name":"NewOwner","type":"event"}] +[{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"certify","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"request","outputs":[],"payable":true,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"},{"name":"_puzzle","type":"bytes32"}],"name":"puzzle","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"uint256"}],"name":"setFee","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"revoke","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_code","type":"bytes32"}],"name":"confirm","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"drain","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"delegate","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setDelegate","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"certified","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"fee","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Requested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"},{"indexed":false,"name":"puzzle","type":"bytes32"}],"name":"Puzzled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Confirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Revoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"old","type":"address"},{"indexed":true,"name":"current","type":"address"}],"name":"NewOwner","type":"event"}] diff --git a/js/src/contracts/badgereg.js b/js/src/contracts/badgereg.js new file mode 100644 index 000000000..f8dbefa78 --- /dev/null +++ b/js/src/contracts/badgereg.js @@ -0,0 +1,66 @@ +// Copyright 2015, 2016 Ethcore (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 . + +import { bytesToHex, hex2Ascii } from '../api/util/format'; + +import ABI from './abi/certifier.json'; + +const ZERO = '0x0000000000000000000000000000000000000000000000000000000000000000'; + +export default class BadgeReg { + constructor (api, registry) { + this._api = api; + this._registry = registry; + + registry.getContract('badgereg'); + this.certifiers = {}; // by name + this.contracts = {}; // by name + } + + fetchCertifier (name) { + if (this.certifiers[name]) { + return Promise.resolve(this.certifiers[name]); + } + return this._registry.getContract('badgereg') + .then((badgeReg) => { + return badgeReg.instance.fromName.call({}, [name]) + .then(([ id, address ]) => { + return Promise.all([ + badgeReg.instance.meta.call({}, [id, 'TITLE']), + badgeReg.instance.meta.call({}, [id, 'IMG']) + ]) + .then(([ title, img ]) => { + title = bytesToHex(title); + title = title === ZERO ? null : hex2Ascii(title); + if (bytesToHex(img) === ZERO) img = null; + + const data = { address, name, title, icon: img }; + this.certifiers[name] = data; + return data; + }); + }); + }); + } + + checkIfCertified (certifier, address) { + if (!this.contracts[certifier]) { + this.contracts[certifier] = this._api.newContract(ABI, certifier); + } + const contract = this.contracts[certifier]; + + return contract.instance.certified.call({}, [address]); + } +} diff --git a/js/src/contracts/contracts.js b/js/src/contracts/contracts.js index 9d745762c..f61a63690 100644 --- a/js/src/contracts/contracts.js +++ b/js/src/contracts/contracts.js @@ -19,7 +19,8 @@ import Registry from './registry'; import SignatureReg from './signaturereg'; import TokenReg from './tokenreg'; import GithubHint from './githubhint'; -import smsVerification from './sms-verification'; +import * as smsVerification from './sms-verification'; +import BadgeReg from './badgereg'; let instance = null; @@ -33,6 +34,7 @@ export default class Contracts { this._signaturereg = new SignatureReg(api, this._registry); this._tokenreg = new TokenReg(api, this._registry); this._githubhint = new GithubHint(api, this._registry); + this.badgeReg = new BadgeReg(api, this._registry); } get registry () { diff --git a/js/src/contracts/registry.js b/js/src/contracts/registry.js index d52b20718..2f61f7f4a 100644 --- a/js/src/contracts/registry.js +++ b/js/src/contracts/registry.js @@ -21,25 +21,39 @@ export default class Registry { this._api = api; this._contracts = []; this._instance = null; + this._fetching = false; + this._queue = []; this.getInstance(); } getInstance () { - return new Promise((resolve, reject) => { - if (this._instance) { - resolve(this._instance); - return; - } + if (this._instance) { + return Promise.resolve(this._instance); + } - this._api.parity - .registryAddress() - .then((address) => { - this._instance = this._api.newContract(abis.registry, address).instance; - resolve(this._instance); - }) - .catch(reject); - }); + if (this._fetching) { + return new Promise((resolve) => { + this._queue.push({ resolve }); + }); + } + + this._fetching = true; + + return this._api.parity + .registryAddress() + .then((address) => { + this._fetching = false; + this._instance = this._api.newContract(abis.registry, address).instance; + + this._queue.forEach((queued) => { + queued.resolve(this._instance); + }); + + this._queue = []; + + return this._instance; + }); } getContract (_name) { diff --git a/js/src/contracts/sms-verification.js b/js/src/contracts/sms-verification.js index e93d57ffc..34a6bad76 100644 --- a/js/src/contracts/sms-verification.js +++ b/js/src/contracts/sms-verification.js @@ -14,39 +14,74 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import { stringify } from 'querystring'; +import subscribeToEvent from '../util/subscribe-to-event'; export const checkIfVerified = (contract, account) => { return contract.instance.certified.call({}, [account]); }; export const checkIfRequested = (contract, account) => { + let subId = null; + let resolved = false; + return new Promise((resolve, reject) => { - contract.subscribe('Requested', { - fromBlock: 0, toBlock: 'pending' - }, (err, logs) => { - if (err) { - return reject(err); - } - const e = logs.find((l) => { - return l.type === 'mined' && l.params.who && l.params.who.value === account; + contract + .subscribe('Requested', { + fromBlock: 0, toBlock: 'pending' + }, (err, logs) => { + if (err) { + return reject(err); + } + const e = logs.find((l) => { + return l.type === 'mined' && l.params.who && l.params.who.value === account; + }); + + resolve(e ? e.transactionHash : false); + resolved = true; + + if (subId) { + contract.unsubscribe(subId); + } + }) + .then((_subId) => { + subId = _subId; + + if (resolved) { + contract.unsubscribe(subId); + } }); - resolve(e ? e.transactionHash : false); - }); }); }; -export const postToServer = (query) => { - query = stringify(query); - return fetch('https://sms-verification.parity.io/?' + query, { - method: 'POST', mode: 'cors', cache: 'no-store' - }) - .then((res) => { - return res.json().then((data) => { - if (res.ok) { - return data.message; +const blockNumber = (api) => { + return new Promise((resolve, reject) => { + api.subscribe('eth_blockNumber', (err, block) => { + if (err) { + return reject(err); } - throw new Error(data.message || 'unknown error'); - }); + resolve(block); + }) + .then((subscription) => { + api.unsubscribe(subscription); + }) + .catch(reject); }); }; + +export const awaitPuzzle = (api, contract, account) => { + return blockNumber(api) + .then((block) => { + return new Promise((resolve, reject) => { + const subscription = subscribeToEvent(contract, 'Puzzled', { + from: block.toNumber(), + filter: (log) => log.params.who.value === account + }); + subscription.once('error', reject); + subscription.once('log', subscription.unsubscribe); + subscription.once('log', resolve); + subscription.once('timeout', () => { + reject(new Error('Timed out waiting for the puzzle.')); + }); + }); + }); +}; diff --git a/js/src/dapps/basiccoin.html b/js/src/dapps/basiccoin.html deleted file mode 100644 index 52bc8bc57..000000000 --- a/js/src/dapps/basiccoin.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - Basic Token Deployment - - -
- - - - - - diff --git a/js/src/dapps/basiccoin.js b/js/src/dapps/basiccoin.js index e02990d14..a64afa0b9 100644 --- a/js/src/dapps/basiccoin.js +++ b/js/src/dapps/basiccoin.js @@ -32,7 +32,6 @@ const routerHistory = useRouterHistory(createHashHistory)({}); import '../../assets/fonts/Roboto/font.css'; import '../../assets/fonts/RobotoMono/font.css'; import './style.css'; -import './basiccoin.html'; ReactDOM.render( diff --git a/js/src/dapps/basiccoin/services.js b/js/src/dapps/basiccoin/services.js index 4aed4199f..3dd5202a7 100644 --- a/js/src/dapps/basiccoin/services.js +++ b/js/src/dapps/basiccoin/services.js @@ -105,7 +105,7 @@ export function attachInstances () { ]) .then(([registryAddress, netChain]) => { const registry = api.newContract(abis.registry, registryAddress).instance; - isTest = netChain === 'morden' || netChain === 'testnet'; + isTest = ['morden', 'ropsten', 'testnet'].includes(netChain); console.log(`contract was found at registry=${registryAddress}`); console.log(`running on ${netChain}, isTest=${isTest}`); diff --git a/js/src/dapps/dappreg.js b/js/src/dapps/dappreg.js new file mode 100644 index 000000000..9bd96f1a7 --- /dev/null +++ b/js/src/dapps/dappreg.js @@ -0,0 +1,32 @@ +// Copyright 2015, 2016 Ethcore (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 . + +import React from 'react'; +import ReactDOM from 'react-dom'; +import injectTapEventPlugin from 'react-tap-event-plugin'; + +injectTapEventPlugin(); + +import Application from './dappreg/Application'; + +import '../../assets/fonts/Roboto/font.css'; +import '../../assets/fonts/RobotoMono/font.css'; +import './style.css'; + +ReactDOM.render( + , + document.querySelector('#container') +); diff --git a/js/src/dapps/dappreg/Application/application.css b/js/src/dapps/dappreg/Application/application.css new file mode 100644 index 000000000..f171d8127 --- /dev/null +++ b/js/src/dapps/dappreg/Application/application.css @@ -0,0 +1,58 @@ +/* Copyright 2015, 2016 Ethcore (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 . +*/ + +.body { + color: #333; + background: #eee; + padding: 4.5em 0; + text-align: center; +} + +.apps { + background: #fff; + border-radius: 0.5em; + margin: 0 auto; + max-width: 980px; + padding: 1.5em; + text-align: left; +} + +.footer { + font-size: 0.75em; + margin: 1em; + padding: 1.5em; + text-align: center; +} + +.header { + background: #44e; + border-radius: 0 0 0.25em 0.25em; + color: #fff; + left: 0; + padding: 1em; + position: fixed; + right: 0; + top: 0; + z-index: 25; +} + +.loading { + text-align: center; + padding-top: 5em; + font-size: 2em; + color: #999; +} diff --git a/js/src/dapps/dappreg/Application/application.js b/js/src/dapps/dappreg/Application/application.js new file mode 100644 index 000000000..b5e4d5a97 --- /dev/null +++ b/js/src/dapps/dappreg/Application/application.js @@ -0,0 +1,64 @@ +// Copyright 2015, 2016 Ethcore (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 . + +import React, { Component } from 'react'; +import { observer } from 'mobx-react'; + +import DappsStore from '../dappsStore'; + +import ButtonBar from '../ButtonBar'; +import Dapp from '../Dapp'; +import ModalDelete from '../ModalDelete'; +import ModalRegister from '../ModalRegister'; +import ModalUpdate from '../ModalUpdate'; +import SelectDapp from '../SelectDapp'; +import Warning from '../Warning'; +import styles from './application.css'; + +@observer +export default class Application extends Component { + dappsStore = DappsStore.instance(); + + render () { + if (this.dappsStore.isLoading) { + return ( +
+ Loading application +
+ ); + } + + return ( +
+
+ DAPP REGISTRY, a global view of distributed applications available on the network. Putting the puzzle together. +
+
+ + + +
+
+ { this.dappsStore.count } applications registered, { this.dappsStore.ownedCount } owned by user +
+ + + + +
+ ); + } +} diff --git a/js/src/views/Account/Transactions/Transaction/index.js b/js/src/dapps/dappreg/Application/index.js similarity index 94% rename from js/src/views/Account/Transactions/Transaction/index.js rename to js/src/dapps/dappreg/Application/index.js index 28a39ad46..236578226 100644 --- a/js/src/views/Account/Transactions/Transaction/index.js +++ b/js/src/dapps/dappreg/Application/index.js @@ -14,4 +14,4 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -export default from './transaction'; +export default from './application'; diff --git a/js/src/dapps/dappreg/Button/button.css b/js/src/dapps/dappreg/Button/button.css new file mode 100644 index 000000000..a66736e46 --- /dev/null +++ b/js/src/dapps/dappreg/Button/button.css @@ -0,0 +1,38 @@ +/* Copyright 2015, 2016 Ethcore (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 . +*/ + +.button { + background: #44e; + border: none; + border-radius: 0.25em; + color: #fff; + cursor: pointer; + font-size: 1em; + margin: 1em 0.375em; + opacity: 0.85; + padding: 0.75em 2em; + + &[disabled] { + opacity: 0.5; + cursor: default; + background: #aaa; + } + + &[data-warning="true"] { + background: #e44; + } +} diff --git a/js/src/dapps/dappreg/Button/button.js b/js/src/dapps/dappreg/Button/button.js new file mode 100644 index 000000000..1f3b67b4c --- /dev/null +++ b/js/src/dapps/dappreg/Button/button.js @@ -0,0 +1,52 @@ +// Copyright 2015, 2016 Ethcore (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 . + +import React, { Component, PropTypes } from 'react'; + +import styles from './button.css'; + +export default class Button extends Component { + static propTypes = { + className: PropTypes.string, + disabled: PropTypes.bool, + label: PropTypes.string.isRequired, + warning: PropTypes.bool, + onClick: PropTypes.func.isRequired + } + + render () { + const { className, disabled, label, warning } = this.props; + const classes = `${styles.button} ${className}`; + + return ( + + ); + } + + onClick = (event) => { + if (this.props.disabled) { + return; + } + + this.props.onClick(event); + } +} diff --git a/js/src/views/Signer/components/RequestPendingWeb3/index.js b/js/src/dapps/dappreg/Button/index.js similarity index 94% rename from js/src/views/Signer/components/RequestPendingWeb3/index.js rename to js/src/dapps/dappreg/Button/index.js index f664b571c..f69a65e3d 100644 --- a/js/src/views/Signer/components/RequestPendingWeb3/index.js +++ b/js/src/dapps/dappreg/Button/index.js @@ -14,4 +14,4 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -export default from './RequestPendingWeb3'; +export default from './button'; diff --git a/js/src/dapps/dappreg/ButtonBar/buttonBar.css b/js/src/dapps/dappreg/ButtonBar/buttonBar.css new file mode 100644 index 000000000..0aa84ee29 --- /dev/null +++ b/js/src/dapps/dappreg/ButtonBar/buttonBar.css @@ -0,0 +1,21 @@ +/* Copyright 2015, 2016 Ethcore (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 . +*/ + +.buttonbar { + text-align: center; + margin: 1em 0 0 0; +} diff --git a/js/src/dapps/dappreg/ButtonBar/buttonBar.js b/js/src/dapps/dappreg/ButtonBar/buttonBar.js new file mode 100644 index 000000000..074c527d0 --- /dev/null +++ b/js/src/dapps/dappreg/ButtonBar/buttonBar.js @@ -0,0 +1,101 @@ +// Copyright 2015, 2016 Ethcore (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 . + +import React, { Component } from 'react'; +import { observer } from 'mobx-react'; + +import DappsStore from '../dappsStore'; +import ModalStore from '../modalStore'; + +import Button from '../Button'; +import styles from './buttonBar.css'; + +@observer +export default class ButtonBar extends Component { + dappsStore = DappsStore.instance(); + modalStore = ModalStore.instance(); + + render () { + let buttons = []; + + if (this.dappsStore.isEditing || this.dappsStore.isNew) { + buttons = [ +