diff --git a/.travis.yml b/.travis.yml index 91c50fa13..f7ac723e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,20 +8,43 @@ branches: - /^stable-.*$/ - /^beta$/ - /^stable$/ +git: + depth: 3 matrix: - fast_finish: false + fast_finish: true allow_failures: - rust: nightly include: - rust: stable - env: FEATURES="--features travis-beta" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" + env: FEATURES="--features travis-beta" RUN_TESTS="true" + # - rust: beta + # env: FEATURES="--features travis-beta" RUN_TESTS="true" + - rust: stable + env: FEATURES="--features travis-beta" RUN_BUILD="true" + - rust: beta + env: FEATURES="--features travis-beta" RUN_BUILD="true" + - rust: stable + env: FEATURES="--features travis-beta" RUN_COVERAGE="true" + # - rust: nightly + # env: FEATURES="--features travis-nightly" RUN_BENCHES="true" + - rust: nightly + env: FEATURES="--features travis-nightly" RUN_TESTS="true" +env: + global: + # GH_TOKEN + - secure: bumJASbZSU8bxJ0EyPUJmu16AiV9EXOpyOj86Jlq/Ty9CfwGqsSXt96uDyE+OUJf34RUFQMsw0nk37/zC4lcn6kqk2wpuH3N/o85Zo/cVZY/NusBWLQqtT5VbYWsV+u2Ua4Tmmsw8yVYQhYwU2ZOejNpflL+Cs9XGgORp1L+/gMRMC2y5Se6ZhwnKPQlRJ8LGsG1dzjQULxzADIt3/zuspNBS8a2urJwlHfGMkvHDoUWCviP/GXoSqw3TZR7FmKyxE19I8n9+iSvm9+oZZquvcgfUxMHn8Gq/b44UbPvjtFOg2yam4xdWXF/RyWCHdc/R9EHorSABeCbefIsm+zcUF3/YQxwpSxM4IZEeH2rTiC7dcrsKw3XsO16xFQz5YI5Bay+CT/wTdMmJd7DdYz7Dyf+pOvcM9WOf/zorxYWSBOMYy0uzbusU2iyIghQ82s7E/Ahg+WARtPgkuTLSB5aL1oCTBKHqQscMr7lo5Ti6RpWLxEdTQMBznc+bMr+6dEtkEcG9zqc6cE9XX+ox3wTU6+HVMfQ1ltCntJ4UKcw3A6INEbw9wgocQa812CIASQ2fE+SCAbz6JxBjIAlFUnD1lUB7S8PdMPwn9plfQgKQ2A5YZqg6FnBdf0rQXIJYxQWKHXj/rBHSUCT0tHACDlzTA+EwWggvkP5AGIxRxm8jhw= + - TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer -p ethjson" + - ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" + - KCOV_FEATURES="" + - KCOV_CMD="./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov" + - RUN_TESTS="false" + - RUN_COVERAGE="false" + - RUN_BUILD="false" + - RUN_BENCHES="false" cache: apt: true directories: - - target/debug/deps - - target/debug/build - - target/release/deps - - target/release/build + - $TRAVIS_BUILD_DIR/target - $HOME/.cargo addons: apt: @@ -29,22 +52,26 @@ addons: - libcurl4-openssl-dev - libelf-dev - libdw-dev + script: -- cargo build --release --verbose ${FEATURES} -- cargo test --release --verbose ${FEATURES} ${TARGETS} -#- cargo bench --no-run ${FEATURES} ${TARGETS} -- tar cvzf parity${ARCHIVE_SUFFIX}.tar.gz -C target/release parity + - if [ "$RUN_TESTS" = "true" ]; then cargo test --release --verbose ${FEATURES} ${TARGETS}; fi + - if [ "$RUN_BENCHES" = "true" ]; then cargo bench --no-run ${FEATURES} ${TARGETS}; fi + - if [ "$RUN_BUILD" = "true" ]; then cargo build --release --verbose ${FEATURES}; fi + - if [ "$RUN_BUILD" = "true" ]; then tar cvzf parity${ARCHIVE_SUFFIX}.tar.gz -C target/release parity; fi + after_success: | + [ "$RUN_COVERAGE" = "true" ] && wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz && tar xzf master.tar.gz && mkdir kcov-master/build && cd kcov-master/build && cmake .. && make && make install DESTDIR=../tmp && cd ../.. && cargo test --no-run ${KCOV_FEATURES} ${TARGETS} && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_util-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethash-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethsync-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethcore_rpc-* && - ./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov target/debug/deps/ethminer-* && - ./kcov-master/tmp/usr/local/bin/kcov --coveralls-id=${TRAVIS_JOB_ID} --exclude-pattern /usr/,/.cargo,/root/.multirust target/kcov target/debug/parity-* && + $KCOV_CMD target/debug/deps/ethcore_util-* && + $KCOV_CMD target/debug/deps/ethash-* && + $KCOV_CMD target/debug/deps/ethcore-* && + $KCOV_CMD target/debug/deps/ethsync-* && + $KCOV_CMD target/debug/deps/ethcore_rpc-* && + $KCOV_CMD target/debug/deps/ethminer-* && + $KCOV_CMD target/debug/deps/ethjson-* && + $KCOV_CMD target/debug/parity-* && [ $TRAVIS_BRANCH = master ] && [ $TRAVIS_PULL_REQUEST = false ] && [ $TRAVIS_RUST_VERSION = stable ] && @@ -53,10 +80,6 @@ after_success: | pip install --user ghp-import && /home/travis/.local/bin/ghp-import -n target/doc && git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages -env: - global: - # GH_TOKEN - - secure: bumJASbZSU8bxJ0EyPUJmu16AiV9EXOpyOj86Jlq/Ty9CfwGqsSXt96uDyE+OUJf34RUFQMsw0nk37/zC4lcn6kqk2wpuH3N/o85Zo/cVZY/NusBWLQqtT5VbYWsV+u2Ua4Tmmsw8yVYQhYwU2ZOejNpflL+Cs9XGgORp1L+/gMRMC2y5Se6ZhwnKPQlRJ8LGsG1dzjQULxzADIt3/zuspNBS8a2urJwlHfGMkvHDoUWCviP/GXoSqw3TZR7FmKyxE19I8n9+iSvm9+oZZquvcgfUxMHn8Gq/b44UbPvjtFOg2yam4xdWXF/RyWCHdc/R9EHorSABeCbefIsm+zcUF3/YQxwpSxM4IZEeH2rTiC7dcrsKw3XsO16xFQz5YI5Bay+CT/wTdMmJd7DdYz7Dyf+pOvcM9WOf/zorxYWSBOMYy0uzbusU2iyIghQ82s7E/Ahg+WARtPgkuTLSB5aL1oCTBKHqQscMr7lo5Ti6RpWLxEdTQMBznc+bMr+6dEtkEcG9zqc6cE9XX+ox3wTU6+HVMfQ1ltCntJ4UKcw3A6INEbw9wgocQa812CIASQ2fE+SCAbz6JxBjIAlFUnD1lUB7S8PdMPwn9plfQgKQ2A5YZqg6FnBdf0rQXIJYxQWKHXj/rBHSUCT0tHACDlzTA+EwWggvkP5AGIxRxm8jhw= deploy: provider: releases diff --git a/Cargo.lock b/Cargo.lock index 4ed5d1ac2..51b4b2740 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,7 +2,7 @@ name = "parity" version = "1.0.0" dependencies = [ - "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 1.1.1 (git+https://github.com/tomusdrw/rust-ctrlc.git)", "daemonize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)", @@ -41,10 +41,10 @@ dependencies = [ [[package]] name = "aster" -version = "0.13.1" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "syntex_syntax 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -52,7 +52,7 @@ name = "bigint" version = "0.1.0" dependencies = [ "arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "heapsize 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)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -95,11 +95,12 @@ dependencies = [ [[package]] name = "clippy" -version = "0.0.50" +version = "0.0.54" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "regex-syntax 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -138,7 +139,7 @@ source = "git+https://github.com/tomusdrw/rust-ctrlc.git#f4927770f89eca80ec25091 dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -162,7 +163,7 @@ name = "docopt" version = "0.6.78" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "regex 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.58 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -178,7 +179,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.58 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -208,13 +209,14 @@ dependencies = [ name = "ethcore" version = "1.0.0" dependencies = [ - "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.0.0", "ethcore-devtools 1.0.0", "ethcore-util 1.0.0", - "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethjson 0.1.0", + "heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -234,20 +236,20 @@ dependencies = [ name = "ethcore-rpc" version = "1.0.0" dependencies = [ - "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.0.0", "ethcore 1.0.0", "ethcore-util 1.0.0", "ethminer 1.0.0", "ethsync 1.0.0", - "jsonrpc-core 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-http-server 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-http-server 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", "transient-hashmap 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -258,13 +260,13 @@ dependencies = [ "arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "bigint 0.1.0", "chrono 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)", "ethcore-devtools 1.0.0", - "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "igd 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "json-tests 0.1.0", @@ -286,11 +288,23 @@ dependencies = [ "vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ethjson" +version = "0.1.0" +dependencies = [ + "ethcore-util 1.0.0", + "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ethminer" version = "1.0.0" dependencies = [ - "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.0.0", "ethcore-util 1.0.0", @@ -304,12 +318,12 @@ dependencies = [ name = "ethsync" version = "1.0.0" dependencies = [ - "clippy 0.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.0.0", "ethcore-util 1.0.0", "ethminer 1.0.0", - "heapsize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 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)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", @@ -339,11 +353,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "heapsize" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -375,27 +388,27 @@ dependencies = [ "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.38 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hyper" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cookie 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -406,7 +419,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hyper 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.58 (registry+https://github.com/rust-lang/crates.io-index)", "xml-rs 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "xmltree 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -426,23 +439,23 @@ dependencies = [ [[package]] name = "jsonrpc-core" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "jsonrpc-http-server" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hyper 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -450,7 +463,7 @@ name = "kernel32-sys" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -482,7 +495,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "librocksdb-sys" version = "0.2.3" -source = "git+https://github.com/arkpar/rust-rocksdb.git#ebb602fc74b4067f9f51310bdc0401b8e59b7156" +source = "git+https://github.com/arkpar/rust-rocksdb.git#ae44ef33ed1358ffc79aa05ed77839d555daba33" dependencies = [ "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -517,6 +530,14 @@ dependencies = [ "serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "mime" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "mio" version = "0.5.0" @@ -526,11 +547,11 @@ dependencies = [ "libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -539,20 +560,20 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "net2" -version = "0.2.22" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -651,20 +672,20 @@ dependencies = [ [[package]] name = "quasi" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "syntex_syntax 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quasi_codegen" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aster 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", + "aster 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -687,7 +708,7 @@ dependencies = [ [[package]] name = "regex" -version = "0.1.56" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -696,11 +717,6 @@ dependencies = [ "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "regex-syntax" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "regex-syntax" version = "0.3.0" @@ -709,7 +725,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rocksdb" version = "0.4.3" -source = "git+https://github.com/arkpar/rust-rocksdb.git#ebb602fc74b4067f9f51310bdc0401b8e59b7156" +source = "git+https://github.com/arkpar/rust-rocksdb.git#ae44ef33ed1358ffc79aa05ed77839d555daba33" dependencies = [ "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "librocksdb-sys 0.2.3 (git+https://github.com/arkpar/rust-rocksdb.git)", @@ -723,7 +739,7 @@ dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -779,14 +795,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_codegen" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aster 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", + "aster 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quasi 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quasi_codegen 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -826,18 +842,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syntex" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "syntex_syntax 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex_syntax 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syntex_syntax" -version = "0.29.1" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -856,7 +872,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -874,7 +890,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -882,6 +898,14 @@ name = "tiny-keccak" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "toml" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "traitobject" version = "0.0.1" @@ -902,7 +926,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicase" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -973,7 +997,7 @@ dependencies = [ [[package]] name = "winapi" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -986,7 +1010,7 @@ name = "ws2_32-sys" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/Cargo.toml b/Cargo.toml index a7abf8921..e9a25f730 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ fdlimit = { path = "util/fdlimit" } daemonize = "0.2" number_prefix = "0.2" rpassword = "0.1" -clippy = { version = "0.0.50", optional = true } +clippy = { version = "0.0.54", optional = true } ethcore = { path = "ethcore" } ethcore-util = { path = "util" } ethsync = { path = "sync" } diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 77fd0e654..d2f464607 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -17,10 +17,11 @@ ethcore-util = { path = "../util" } evmjit = { path = "../evmjit", optional = true } ethash = { path = "../ethash" } num_cpus = "0.2" -clippy = { version = "0.0.50", optional = true } +clippy = { version = "0.0.54", optional = true } crossbeam = "0.1.5" lazy_static = "0.1" ethcore-devtools = { path = "../devtools" } +ethjson = { path = "../json" } [features] jit = ["evmjit"] diff --git a/ethcore/res/ethereum/frontier.json b/ethcore/res/ethereum/frontier.json index cd66ad3f1..8f9209179 100644 --- a/ethcore/res/ethereum/frontier.json +++ b/ethcore/res/ethereum/frontier.json @@ -33,10 +33,10 @@ "enode://248f12bc8b18d5289358085520ac78cd8076485211e6d96ab0bc93d6cd25442db0ce3a937dc404f64f207b0b9aed50e25e98ce32af5ac7cb321ff285b97de485@parity-node-zero.ethcore.io:30303" ], "accounts": { - "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } }, + "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, "3282791d6fd713f1e94f4bfd565eaa78b3a0599d": { "balance": "1337000000000000000000" }, diff --git a/ethcore/res/ethereum/frontier_like_test.json b/ethcore/res/ethereum/frontier_like_test.json index 3e4108566..376b369c4 100644 --- a/ethcore/res/ethereum/frontier_like_test.json +++ b/ethcore/res/ethereum/frontier_like_test.json @@ -1,5 +1,5 @@ { - "engineName": "Frontier (Test)", + "name": "Frontier (Test)", "engineName": "Ethash", "params": { "accountStartNonce": "0x00", @@ -26,9 +26,9 @@ "gasLimit": "0x1388" }, "accounts": { - "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } } + "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } } } } diff --git a/ethcore/res/ethereum/frontier_test.json b/ethcore/res/ethereum/frontier_test.json index 8ee1cafd9..92e8f5877 100644 --- a/ethcore/res/ethereum/frontier_test.json +++ b/ethcore/res/ethereum/frontier_test.json @@ -1,5 +1,5 @@ { - "engineName": "Frontier (Test)", + "name": "Frontier (Test)", "engineName": "Ethash", "params": { "accountStartNonce": "0x00", @@ -26,9 +26,9 @@ "gasLimit": "0x1388" }, "accounts": { - "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } } + "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } } } } diff --git a/ethcore/res/ethereum/homestead_test.json b/ethcore/res/ethereum/homestead_test.json index 1fb5dff80..0f0e630dd 100644 --- a/ethcore/res/ethereum/homestead_test.json +++ b/ethcore/res/ethereum/homestead_test.json @@ -26,9 +26,9 @@ "gasLimit": "0x1388" }, "accounts": { - "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } } + "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } } } } diff --git a/ethcore/res/ethereum/morden.json b/ethcore/res/ethereum/morden.json index e9f8e0e99..2cf4785db 100644 --- a/ethcore/res/ethereum/morden.json +++ b/ethcore/res/ethereum/morden.json @@ -29,10 +29,10 @@ "enode://b1217cbaa440e35ed471157123fe468e19e8b5ad5bedb4b1fdbcbdab6fb2f5ed3e95dd9c24a22a79fdb2352204cea207df27d92bfd21bfd41545e8b16f637499@104.44.138.37:30303" ], "accounts": { - "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } }, + "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, "102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" } } } diff --git a/ethcore/res/ethereum/olympic.json b/ethcore/res/ethereum/olympic.json index b3dfc1ed8..0cc2e6a57 100644 --- a/ethcore/res/ethereum/olympic.json +++ b/ethcore/res/ethereum/olympic.json @@ -26,10 +26,10 @@ "gasLimit": "0x2fefd8" }, "accounts": { - "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } }, + "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }, "e6716f9544a56c530d868e4bfbacb172315bdead": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }, "b9c015918bdaba24b4ff057a92a3873d6eb201be": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }, diff --git a/ethcore/res/null_morden.json b/ethcore/res/null_morden.json index 46507ff95..70b48fbdb 100644 --- a/ethcore/res/null_morden.json +++ b/ethcore/res/null_morden.json @@ -26,10 +26,10 @@ "gasLimit": "0x2fefd8" }, "accounts": { - "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } }, - "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "linear": { "base": 60, "word": 12 } } }, - "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } }, - "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "linear": { "base": 15, "word": 3 } } }, + "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, "102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" } } } diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index d4aa35445..e53cbfd61 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -438,7 +438,7 @@ mod tests { open_block.push_uncle(uncle1_header).unwrap(); open_block.push_uncle(uncle2_header).unwrap(); let b = open_block.close().seal(engine.deref(), vec![]).unwrap(); - + let orig_bytes = b.rlp_bytes(); let orig_db = b.drain(); diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 40b01c6f9..edbd96458 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -100,6 +100,11 @@ pub trait BlockProvider { self.block(&address.block_hash).and_then(|bytes| BlockView::new(&bytes).localized_transaction_at(address.index)) } + /// Get transaction receipt. + fn transaction_receipt(&self, address: &TransactionAddress) -> Option { + self.block_receipts(&address.block_hash).and_then(|br| br.receipts.into_iter().nth(address.index)) + } + /// Get a list of transactions for a given block. /// Returns None if block does not exist. fn transactions(&self, hash: &H256) -> Option> { diff --git a/ethcore/src/builtin.rs b/ethcore/src/builtin.rs index 5589a2525..2ee8e24b1 100644 --- a/ethcore/src/builtin.rs +++ b/ethcore/src/builtin.rs @@ -19,7 +19,7 @@ use crypto::sha2::Sha256; use crypto::ripemd160::Ripemd160; use crypto::digest::Digest; -/// Definition of a contract whose implementation is built-in. +/// Definition of a contract whose implementation is built-in. pub struct Builtin { /// The gas cost of running this built-in for the given size of input data. pub cost: Box U256>, // TODO: U256 should be bignum. @@ -63,14 +63,16 @@ impl Builtin { /// Create a builtin from JSON. /// - /// JSON must be of the form `{ "name": "identity", "linear": {"base": 10, "word": 20} }`. + /// JSON must be of the form `{ "name": "identity", "pricing": {"base": 10, "word": 20} }`. pub fn from_json(json: &Json) -> Option { // NICE: figure out a more convenient means of handing errors here. if let Json::String(ref name) = json["name"] { - if let Json::Object(ref o) = json["linear"] { - if let Json::U64(ref word) = o["word"] { - if let Json::U64(ref base) = o["base"] { - return Self::from_named_linear(&name[..], *base as usize, *word as usize); + if let Json::Object(ref o) = json["pricing"] { + if let Json::Object(ref o) = o["linear"] { + if let Json::U64(ref word) = o["word"] { + if let Json::U64(ref base) = o["base"] { + return Self::from_named_linear(&name[..], *base as usize, *word as usize); + } } } } @@ -274,7 +276,7 @@ fn from_named_linear() { #[test] fn from_json() { - let text = "{ \"name\": \"identity\", \"linear\": {\"base\": 10, \"word\": 20} }"; + let text = r#"{"name": "identity", "pricing": {"linear": {"base": 10, "word": 20}}}"#; let json = Json::from_str(text).unwrap(); let b = Builtin::from_json(&json).unwrap(); assert_eq!((*b.cost)(0), U256::from(10)); diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index caa92db97..76ee769cf 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -37,6 +37,9 @@ use log_entry::LocalizedLogEntry; use block_queue::{BlockQueue, BlockQueueInfo}; use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute}; use client::{BlockId, TransactionId, ClientConfig, BlockChainClient}; +use env_info::EnvInfo; +use executive::{Executive, Executed}; +use receipt::LocalizedReceipt; pub use blockchain::CacheSize as BlockChainCacheSize; /// General block status @@ -211,6 +214,7 @@ impl Client where V: Verifier { let last_hashes = self.build_last_hashes(header.parent_hash.clone()); let db = self.state_db.lock().unwrap().spawn(); + let enact_result = enact_verified(&block, engine, db, &parent, last_hashes); if let Err(e) = enact_result { warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); @@ -382,16 +386,50 @@ impl Client where V: Verifier { BlockId::Latest => Some(self.chain.best_block_number()) } } + + fn transaction_address(&self, id: TransactionId) -> Option { + match id { + TransactionId::Hash(ref hash) => self.chain.transaction_address(hash), + TransactionId::Location(id, index) => Self::block_hash(&self.chain, id).map(|hash| TransactionAddress { + block_hash: hash, + index: index + }) + } + } } impl BlockChainClient for Client where V: Verifier { + fn call(&self, t: &SignedTransaction) -> Result { + let header = self.block_header(BlockId::Latest).unwrap(); + let view = HeaderView::new(&header); + let last_hashes = self.build_last_hashes(view.hash()); + let env_info = EnvInfo { + number: view.number(), + author: view.author(), + timestamp: view.timestamp(), + difficulty: view.difficulty(), + last_hashes: last_hashes, + gas_used: U256::zero(), + gas_limit: U256::max_value(), + }; + // that's just a copy of the state. + let mut state = self.state(); + let sender = try!(t.sender()); + let balance = state.balance(&sender); + // give the sender max balance + state.sub_balance(&sender, &balance); + state.add_balance(&sender, &U256::max_value()); + Executive::new(&mut state, &env_info, self.engine.deref().deref()).transact(t) + } + // TODO [todr] Should be moved to miner crate eventually. fn try_seal(&self, block: ClosedBlock, seal: Vec) -> Result { block.try_seal(self.engine.deref().deref(), seal) } // TODO [todr] Should be moved to miner crate eventually. - fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec) -> Option { + fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec) + -> Option<(ClosedBlock, HashSet)> { let engine = self.engine.deref().deref(); let h = self.chain.best_block_hash(); @@ -417,21 +455,40 @@ impl BlockChainClient for Client where V: Verifier { // Add transactions let block_number = b.block().header().number(); + let min_tx_gas = U256::from(self.engine.schedule(&b.env_info()).tx_gas); + let mut invalid_transactions = HashSet::new(); + for tx in transactions { + // Push transaction to block + let hash = tx.hash(); let import = b.push_transaction(tx, None); - if let Err(e) = import { - trace!("Error adding transaction to block: number={}. Error: {:?}", block_number, e); + + match import { + Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, .. })) => { + trace!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?}", hash); + // Exit early if gas left is smaller then min_tx_gas + if gas_limit - gas_used < min_tx_gas { + break; + } + }, + Err(e) => { + invalid_transactions.insert(hash); + trace!(target: "miner", + "Error adding transaction to block: number={}. transaction_hash={:?}, Error: {:?}", + block_number, hash, e); + }, + _ => {} } } // And close let b = b.close(); - trace!("Sealing: number={}, hash={}, diff={}", + trace!(target: "miner", "Sealing: number={}, hash={}, diff={}", b.block().header().number(), b.hash(), b.block().header().difficulty() ); - Some(b) + Some((b, invalid_transactions)) } fn block_header(&self, id: BlockId) -> Option { @@ -489,13 +546,43 @@ impl BlockChainClient for Client where V: Verifier { } fn transaction(&self, id: TransactionId) -> Option { - match id { - TransactionId::Hash(ref hash) => self.chain.transaction_address(hash), - TransactionId::Location(id, index) => Self::block_hash(&self.chain, id).map(|hash| TransactionAddress { - block_hash: hash, - index: index - }) - }.and_then(|address| self.chain.transaction(&address)) + self.transaction_address(id).and_then(|address| self.chain.transaction(&address)) + } + + fn transaction_receipt(&self, id: TransactionId) -> Option { + self.transaction_address(id).and_then(|address| { + let t = self.chain.block(&address.block_hash) + .and_then(|block| BlockView::new(&block).localized_transaction_at(address.index)); + + match (t, self.chain.transaction_receipt(&address)) { + (Some(tx), Some(receipt)) => { + let block_hash = tx.block_hash.clone(); + let block_number = tx.block_number.clone(); + let transaction_hash = tx.hash(); + let transaction_index = tx.transaction_index; + Some(LocalizedReceipt { + transaction_hash: tx.hash(), + transaction_index: tx.transaction_index, + block_hash: tx.block_hash, + block_number: tx.block_number, + // TODO: to fix this, query all previous transaction receipts and retrieve their gas usage + cumulative_gas_used: receipt.gas_used, + gas_used: receipt.gas_used, + // TODO: to fix this, store created contract address in db + contract_address: None, + logs: receipt.logs.into_iter().enumerate().map(|(i, log)| LocalizedLogEntry { + entry: log, + block_hash: block_hash.clone(), + block_number: block_number, + transaction_hash: transaction_hash.clone(), + transaction_index: transaction_index, + log_index: i + }).collect() + }) + }, + _ => None + } + }) } fn tree_route(&self, from: &H256, to: &H256) -> Option { @@ -580,7 +667,7 @@ impl BlockChainClient for Client where V: Verifier { .map(|(i, log)| LocalizedLogEntry { entry: log, block_hash: hash.clone(), - block_number: number as usize, + block_number: number, transaction_hash: hashes.get(index).cloned().unwrap_or_else(H256::new), transaction_index: index, log_index: log_index + i diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 88e07d0b1..74b05652f 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -25,7 +25,9 @@ pub use self::client::*; pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig}; pub use self::ids::{BlockId, TransactionId}; pub use self::test_client::{TestBlockChainClient, EachBlockWith}; +pub use executive::Executed; +use std::collections::HashSet; use util::bytes::Bytes; use util::hash::{Address, H256, H2048}; use util::numbers::U256; @@ -36,7 +38,8 @@ use header::BlockNumber; use transaction::{LocalizedTransaction, SignedTransaction}; use log_entry::LocalizedLogEntry; use filter::Filter; -use error::{ImportResult}; +use error::{ImportResult, Error}; +use receipt::LocalizedReceipt; /// Blockchain database client. Owns and manages a blockchain and a block queue. pub trait BlockChainClient : Sync + Send { @@ -74,6 +77,9 @@ pub trait BlockChainClient : Sync + Send { /// Get transaction with given hash. fn transaction(&self, id: TransactionId) -> Option; + /// Get transaction receipt with given hash. + fn transaction_receipt(&self, id: TransactionId) -> Option; + /// Get a tree route between `from` and `to`. /// See `BlockChain::tree_route`. fn tree_route(&self, from: &H256, to: &H256) -> Option; @@ -110,11 +116,14 @@ pub trait BlockChainClient : Sync + Send { // TODO [todr] Should be moved to miner crate eventually. /// Returns ClosedBlock prepared for sealing. - fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec) -> Option; + fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec) + -> Option<(ClosedBlock, HashSet)>; // TODO [todr] Should be moved to miner crate eventually. /// Attempts to seal given block. Returns `SealedBlock` on success and the same block in case of error. fn try_seal(&self, block: ClosedBlock, seal: Vec) -> Result; + /// Makes a non-persistent transaction call. + fn call(&self, t: &SignedTransaction) -> Result; } diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 83511b1cc..48c16ac10 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -23,12 +23,14 @@ use client::{BlockChainClient, BlockChainInfo, BlockStatus, BlockId, Transaction use header::{Header as BlockHeader, BlockNumber}; use filter::Filter; use log_entry::LocalizedLogEntry; -use receipt::Receipt; +use receipt::{Receipt, LocalizedReceipt}; use extras::BlockReceipts; use error::{ImportResult}; use block_queue::BlockQueueInfo; use block::{SealedBlock, ClosedBlock}; +use executive::Executed; +use error::Error; /// Test client. pub struct TestBlockChainClient { @@ -48,6 +50,8 @@ pub struct TestBlockChainClient { pub storage: RwLock>, /// Code. pub code: RwLock>, + /// Execution result. + pub execution_result: RwLock>, } #[derive(Clone)] @@ -82,12 +86,18 @@ impl TestBlockChainClient { balances: RwLock::new(HashMap::new()), storage: RwLock::new(HashMap::new()), code: RwLock::new(HashMap::new()), + execution_result: RwLock::new(None), }; client.add_blocks(1, EachBlockWith::Nothing); // add genesis block client.genesis_hash = client.last_hash.read().unwrap().clone(); client } + /// Set the execution result. + pub fn set_execution_result(&self, result: Executed) { + *self.execution_result.write().unwrap() = Some(result); + } + /// Set the balance of account `address` to `balance`. pub fn set_balance(&self, address: Address, balance: U256) { self.balances.write().unwrap().insert(address, balance); @@ -111,6 +121,7 @@ impl TestBlockChainClient { header.difficulty = From::from(n); header.parent_hash = self.last_hash.read().unwrap().clone(); header.number = n as BlockNumber; + header.gas_limit = U256::from(1_000_000); let uncles = match with { EachBlockWith::Uncle | EachBlockWith::UncleAndTransaction => { let mut uncles = RlpStream::new_list(1); @@ -181,6 +192,10 @@ impl TestBlockChainClient { } impl BlockChainClient for TestBlockChainClient { + fn call(&self, _t: &SignedTransaction) -> Result { + Ok(self.execution_result.read().unwrap().clone().unwrap()) + } + fn block_total_difficulty(&self, _id: BlockId) -> Option { Some(U256::zero()) } @@ -209,6 +224,10 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } + fn transaction_receipt(&self, _id: TransactionId) -> Option { + unimplemented!(); + } + fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockId, _to_block: BlockId) -> Option> { unimplemented!(); } @@ -217,12 +236,12 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } - fn prepare_sealing(&self, _author: Address, _gas_floor_target: U256, _extra_data: Bytes, _transactions: Vec) -> Option { - unimplemented!() + fn prepare_sealing(&self, _author: Address, _gas_floor_target: U256, _extra_data: Bytes, _transactions: Vec) -> Option<(ClosedBlock, HashSet)> { + None } - fn try_seal(&self, _block: ClosedBlock, _seal: Vec) -> Result { - unimplemented!() + fn try_seal(&self, block: ClosedBlock, _seal: Vec) -> Result { + Err(block) } fn block_header(&self, id: BlockId) -> Option { diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index 72127c754..02cd6678b 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -65,12 +65,30 @@ pub enum ExecutionError { #[derive(Debug)] /// Errors concerning transaction processing. pub enum TransactionError { + /// Transaction is already imported to the queue + AlreadyImported, + /// Transaction is not valid anymore (state already has higher nonce) + Old, /// Transaction's gas price is below threshold. InsufficientGasPrice { /// Minimal expected gas price minimal: U256, /// Transaction gas price - got: U256 + got: U256, + }, + /// Sender doesn't have enough funds to pay for this transaction + InsufficientBalance { + /// Senders balance + balance: U256, + /// Transaction cost + cost: U256, + }, + /// Transactions gas is higher then current gas limit + GasLimitExceeded { + /// Current gas limit + limit: U256, + /// Declared transaction gas + got: U256, }, /// Transaction's gas limit (aka gas) is invalid. InvalidGasLimit(OutOfBounds), diff --git a/ethcore/src/evm/ext.rs b/ethcore/src/evm/ext.rs index f4172f10a..4986b12c8 100644 --- a/ethcore/src/evm/ext.rs +++ b/ethcore/src/evm/ext.rs @@ -67,6 +67,7 @@ pub trait Ext { /// Returns Err, if we run out of gas. /// Otherwise returns call_result which contains gas left /// and true if subcall was successfull. + #[cfg_attr(feature="dev", allow(too_many_arguments))] fn call(&mut self, gas: &U256, sender_address: &Address, diff --git a/ethcore/src/evm/interpreter.rs b/ethcore/src/evm/interpreter.rs index 7491321cb..b29fc0d41 100644 --- a/ethcore/src/evm/interpreter.rs +++ b/ethcore/src/evm/interpreter.rs @@ -521,6 +521,7 @@ impl Interpreter { Ok(overflowing!(offset.overflowing_add(size.clone()))) } + #[cfg_attr(feature="dev", allow(too_many_arguments))] fn exec_instruction(&self, gas: Gas, params: &ActionParams, diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 782063cb2..9aa3bcf9b 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -37,7 +37,7 @@ pub fn contract_address(address: &Address, nonce: &U256) -> Address { } /// Transaction execution receipt. -#[derive(Debug)] +#[derive(Debug, PartialEq, Clone)] pub struct Executed { /// Gas paid up front for execution of transaction. pub gas: U256, @@ -60,7 +60,9 @@ pub struct Executed { /// eg. sender creates contract A and A in constructor creates contract B /// /// B creation ends first, and it will be the first element of the vector. - pub contracts_created: Vec
+ pub contracts_created: Vec
, + /// Transaction output. + pub output: Bytes, } /// Transaction execution result. @@ -145,7 +147,7 @@ impl<'a> Executive<'a> { let mut substate = Substate::new(); - let res = match t.action { + let (gas_left, output) = match t.action { Action::Create => { let new_address = contract_address(&sender, &nonce); let params = ActionParams { @@ -159,7 +161,7 @@ impl<'a> Executive<'a> { code: Some(t.data.clone()), data: None, }; - self.create(params, &mut substate) + (self.create(params, &mut substate), vec![]) }, Action::Call(ref address) => { let params = ActionParams { @@ -175,12 +177,12 @@ impl<'a> Executive<'a> { }; // TODO: move output upstream let mut out = vec![]; - self.call(params, &mut substate, BytesRef::Flexible(&mut out)) + (self.call(params, &mut substate, BytesRef::Flexible(&mut out)), out) } }; // finalize here! - Ok(try!(self.finalize(t, substate, res))) + Ok(try!(self.finalize(t, substate, gas_left, output))) } fn exec_vm(&mut self, params: ActionParams, unconfirmed_substate: &mut Substate, output_policy: OutputPolicy) -> evm::Result { @@ -286,7 +288,7 @@ impl<'a> Executive<'a> { } /// Finalizes the transaction (does refunds and suicides). - fn finalize(&mut self, t: &SignedTransaction, substate: Substate, result: evm::Result) -> ExecutionResult { + fn finalize(&mut self, t: &SignedTransaction, substate: Substate, result: evm::Result, output: Bytes) -> ExecutionResult { let schedule = self.engine.schedule(self.info); // refunds from SSTORE nonzero -> zero @@ -326,7 +328,8 @@ impl<'a> Executive<'a> { refunded: U256::zero(), cumulative_gas_used: self.info.gas_used + t.gas, logs: vec![], - contracts_created: vec![] + contracts_created: vec![], + output: output, }) }, _ => { @@ -337,6 +340,7 @@ impl<'a> Executive<'a> { cumulative_gas_used: self.info.gas_used + gas_used, logs: substate.logs, contracts_created: substate.contracts_created, + output: output, }) }, } diff --git a/ethcore/src/json_tests/chain.rs b/ethcore/src/json_tests/chain.rs index 89bd5da2b..a2e6a5659 100644 --- a/ethcore/src/json_tests/chain.rs +++ b/ethcore/src/json_tests/chain.rs @@ -16,18 +16,19 @@ use super::test_common::*; use client::{BlockChainClient, Client, ClientConfig}; -use pod_state::*; use block::Block; use ethereum; use tests::helpers::*; use devtools::*; +use spec::Genesis; +use ethjson; pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { init_log(); - let json = Json::from_str(::std::str::from_utf8(json_data).unwrap()).expect("Json is invalid"); + let tests = ethjson::blockchain::Test::load(json_data).unwrap(); let mut failed = Vec::new(); - for (name, test) in json.as_object().unwrap() { + for (name, blockchain) in tests.deref() { let mut fail = false; { let mut fail_unless = |cond: bool| if !cond && !fail { @@ -39,37 +40,36 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { flush!(" - {}...", name); - let blocks: Vec<(Bytes, bool)> = test["blocks"].as_array().unwrap().iter().map(|e| (xjson!(&e["rlp"]), e.find("blockHeader").is_some())).collect(); let mut spec = match era { ChainEra::Frontier => ethereum::new_frontier_test(), ChainEra::Homestead => ethereum::new_homestead_test(), }; - let s = PodState::from_json(test.find("pre").unwrap()); - spec.set_genesis_state(s); - spec.overwrite_genesis(test.find("genesisBlockHeader").unwrap()); + + let genesis = Genesis::from(blockchain.genesis()); + let state = From::from(blockchain.pre_state.clone()); + spec.set_genesis_state(state); + spec.overwrite_genesis_params(genesis); assert!(spec.is_state_root_valid()); - let genesis_hash = spec.genesis_header().hash(); - assert_eq!(genesis_hash, H256::from_json(&test.find("genesisBlockHeader").unwrap()["hash"])); let temp = RandomTempPath::new(); { let client = Client::new(ClientConfig::default(), spec, temp.as_path(), IoChannel::disconnected()).unwrap(); - assert_eq!(client.chain_info().best_block_hash, genesis_hash); - for (b, is_valid) in blocks.into_iter() { + for b in &blockchain.blocks_rlp() { if Block::is_good(&b) { let _ = client.import_block(b.clone()); + client.flush_queue(); + client.import_verified_blocks(&IoChannel::disconnected()); } - client.flush_queue(); - let imported_ok = client.import_verified_blocks(&IoChannel::disconnected()) > 0; - assert_eq!(imported_ok, is_valid); } - fail_unless(client.chain_info().best_block_hash == H256::from_json(&test["lastblockhash"])); + fail_unless(client.chain_info().best_block_hash == blockchain.best_block.clone().into()); } } + if !fail { flushln!("ok"); } } + println!("!!! {:?} tests from failed.", failed.len()); failed } diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 572cda2fa..dfa321639 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -83,6 +83,7 @@ extern crate time; extern crate env_logger; extern crate num_cpus; extern crate crossbeam; +extern crate ethjson; #[cfg(test)] extern crate ethcore_devtools as devtools; #[cfg(feature = "jit" )] extern crate evmjit; @@ -100,13 +101,13 @@ pub mod spec; pub mod transaction; pub mod views; pub mod receipt; +pub mod pod_state; mod common; mod basic_types; #[macro_use] mod evm; mod env_info; mod pod_account; -mod pod_state; mod account_diff; mod state_diff; mod engine; diff --git a/ethcore/src/log_entry.rs b/ethcore/src/log_entry.rs index 63d09b4f0..cf74a6df9 100644 --- a/ethcore/src/log_entry.rs +++ b/ethcore/src/log_entry.rs @@ -18,6 +18,7 @@ use util::*; use basic_types::LogBloom; +use header::BlockNumber; /// A record of execution for a `LOG` operation. #[derive(Default, Debug, Clone, PartialEq, Eq)] @@ -84,7 +85,7 @@ pub struct LocalizedLogEntry { /// Block in which this log was created. pub block_hash: H256, /// Block number. - pub block_number: usize, + pub block_number: BlockNumber, /// Hash of transaction in which this log was created. pub transaction_hash: H256, /// Index of transaction within block. diff --git a/ethcore/src/pod_account.rs b/ethcore/src/pod_account.rs index d2690051c..387679da9 100644 --- a/ethcore/src/pod_account.rs +++ b/ethcore/src/pod_account.rs @@ -17,6 +17,7 @@ use util::*; use account::*; use account_db::*; +use ethjson; #[derive(Debug,Clone,PartialEq,Eq)] /// An account, expressed as Plain-Old-Data (hence the name). @@ -73,6 +74,22 @@ impl PodAccount { } } +impl From for PodAccount { + fn from(a: ethjson::blockchain::Account) -> Self { + PodAccount { + balance: a.balance.into(), + nonce: a.nonce.into(), + code: a.code.into(), + storage: a.storage.into_iter().fold(BTreeMap::new(), |mut acc, (key, value)| { + let key: U256 = key.into(); + let value: U256 = value.into(); + acc.insert(H256::from(key), H256::from(value)); + acc + }) + } + } +} + impl fmt::Display for PodAccount { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "(bal={}; nonce={}; code={} bytes, #{}; storage={} items)", self.balance, self.nonce, self.code.len(), self.code.sha3(), self.storage.len()) diff --git a/ethcore/src/pod_state.rs b/ethcore/src/pod_state.rs index b873249ac..7ebfed78b 100644 --- a/ethcore/src/pod_state.rs +++ b/ethcore/src/pod_state.rs @@ -14,11 +14,14 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! State of all accounts in the system expressed in Plain Old Data. + use util::*; use pod_account::*; +use ethjson; -#[derive(Debug,Clone,PartialEq,Eq,Default)] /// State of all accounts in the system expressed in Plain Old Data. +#[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct PodState (BTreeMap); impl PodState { @@ -64,6 +67,15 @@ impl FromJson for PodState { } } +impl From for PodState { + fn from(s: ethjson::blockchain::State) -> PodState { + PodState(s.0.into_iter().fold(BTreeMap::new(), |mut acc, (key, value)| { + acc.insert(key.into(), PodAccount::from(value)); + acc + })) + } +} + impl fmt::Display for PodState { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for (add, acc) in &self.0 { diff --git a/ethcore/src/receipt.rs b/ethcore/src/receipt.rs index ae83a174a..7f0b0d8dd 100644 --- a/ethcore/src/receipt.rs +++ b/ethcore/src/receipt.rs @@ -18,7 +18,8 @@ use util::*; use basic_types::LogBloom; -use log_entry::LogEntry; +use header::BlockNumber; +use log_entry::{LogEntry, LocalizedLogEntry}; /// Information describing execution of a transaction. #[derive(Default, Debug, Clone)] @@ -74,6 +75,26 @@ impl HeapSizeOf for Receipt { } } +/// Receipt with additional info. +pub struct LocalizedReceipt { + /// Transaction hash. + pub transaction_hash: H256, + /// Transaction index. + pub transaction_index: usize, + /// Block hash. + pub block_hash: H256, + /// Block number. + pub block_number: BlockNumber, + /// Cumulative gas used. + pub cumulative_gas_used: U256, + /// Gas used. + pub gas_used: U256, + /// Contract address. + pub contract_address: Option
, + /// Logs + pub logs: Vec, +} + #[test] fn test_basic() { let expected = FromHex::from_hex("f90162a02f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee83040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap(); diff --git a/ethcore/src/spec/genesis.rs b/ethcore/src/spec/genesis.rs new file mode 100644 index 000000000..686e8f6d1 --- /dev/null +++ b/ethcore/src/spec/genesis.rs @@ -0,0 +1,91 @@ +// 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 . + +use util::rlp::*; +use util::numbers::{Uint, U256}; +use util::hash::{H64, Address, H256}; +use ethjson; + +/// Genesis seal type. +pub enum Seal { + /// Classic ethereum seal. + Ethereum { + /// Seal nonce. + nonce: H64, + /// Seal mix hash. + mix_hash: H256, + }, + /// Generic seal. + Generic { + /// Number of seal fields. + fields: usize, + /// Seal rlp. + rlp: Vec, + }, +} + +/// Genesis components. +pub struct Genesis { + /// Seal. + pub seal: Seal, + /// Difficulty. + pub difficulty: U256, + /// Author. + pub author: Address, + /// Timestamp. + pub timestamp: u64, + /// Parent hash. + pub parent_hash: H256, + /// Gas limit. + pub gas_limit: U256, + /// Transactions root. + pub transactions_root: H256, + /// Receipts root. + pub receipts_root: H256, + /// State root. + pub state_root: Option, + /// Gas used. + pub gas_used: U256, + /// Extra data. + pub extra_data: Vec, +} + +impl From for Genesis { + fn from(g: ethjson::spec::Genesis) -> Self { + Genesis { + seal: match (g.nonce, g.mix_hash) { + (Some(nonce), Some(mix_hash)) => Seal::Ethereum { + nonce: nonce.into(), + mix_hash: mix_hash.into(), + }, + _ => Seal::Generic { + fields: g.seal_fields.unwrap(), + rlp: g.seal_rlp.unwrap().into(), + } + }, + difficulty: g.difficulty.into(), + author: g.author.into(), + timestamp: g.timestamp.into(), + parent_hash: g.parent_hash.into(), + gas_limit: g.gas_limit.into(), + transactions_root: g.transactions_root.map_or_else(|| SHA3_NULL_RLP.clone(), Into::into), + receipts_root: g.receipts_root.map_or_else(|| SHA3_NULL_RLP.clone(), Into::into), + state_root: g.state_root.map(Into::into), + gas_used: g.gas_used.map_or_else(U256::zero, Into::into), + extra_data: g.extra_data.map_or_else(Vec::new, Into::into), + } + } +} diff --git a/ethcore/src/spec/mod.rs b/ethcore/src/spec/mod.rs new file mode 100644 index 000000000..b85165d89 --- /dev/null +++ b/ethcore/src/spec/mod.rs @@ -0,0 +1,23 @@ +// 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 . + +//! Blockchain params. + +mod genesis; +pub mod spec; + +pub use self::spec::*; +pub use self::genesis::Genesis; diff --git a/ethcore/src/spec.rs b/ethcore/src/spec/spec.rs similarity index 92% rename from ethcore/src/spec.rs rename to ethcore/src/spec/spec.rs index 2208350cc..c7e2e4e9f 100644 --- a/ethcore/src/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -21,6 +21,8 @@ use engine::*; use pod_state::*; use null_engine::*; use account_db::*; +use ethereum; +use super::genesis::{Seal as GenesisSeal, Genesis}; /// Convert JSON value to equivalent RLP representation. // TODO: handle container types. @@ -106,7 +108,7 @@ impl Spec { pub fn to_engine(self) -> Result, Error> { match self.engine_name.as_ref() { "NullEngine" => Ok(NullEngine::new_boxed(self)), - "Ethash" => Ok(super::ethereum::Ethash::new_boxed(self)), + "Ethash" => Ok(ethereum::Ethash::new_boxed(self)), _ => Err(Error::UnknownEngineName(self.engine_name.clone())) } } @@ -197,6 +199,32 @@ impl Spec { self.state_root_memo = RwLock::new(genesis.find("stateRoot").and_then(|_| Some(H256::from_json(&genesis["stateRoot"])))); } + /// Overwrite the genesis components. + pub fn overwrite_genesis_params(&mut self, g: Genesis) { + let (seal_fields, seal_rlp) = match g.seal { + GenesisSeal::Generic { fields, rlp } => (fields, rlp), + GenesisSeal::Ethereum { nonce, mix_hash } => { + let mut s = RlpStream::new(); + s.append(&mix_hash); + s.append(&nonce); + (2, s.out()) + } + }; + + self.parent_hash = g.parent_hash; + self.transactions_root = g.transactions_root; + self.receipts_root = g.receipts_root; + self.author = g.author; + self.difficulty = g.difficulty; + self.gas_limit = g.gas_limit; + self.gas_used = g.gas_used; + self.timestamp = g.timestamp; + self.extra_data = g.extra_data; + self.seal_fields = seal_fields; + self.seal_rlp = seal_rlp; + self.state_root_memo = RwLock::new(g.state_root); + } + /// Alter the value of the genesis state. pub fn set_genesis_state(&mut self, s: PodState) { self.genesis_state = s; @@ -304,7 +332,7 @@ impl Spec { } /// Create a new Spec which conforms to the Morden chain except that it's a NullEngine consensus. - pub fn new_test() -> Spec { Self::from_json_utf8(include_bytes!("../res/null_morden.json")) } + pub fn new_test() -> Spec { Self::from_json_utf8(include_bytes!("../../res/null_morden.json")) } } #[cfg(test)] diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index d9fae0527..64a2222b1 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -144,7 +144,7 @@ fn can_mine() { let client_result = get_test_client_with_blocks(vec![dummy_blocks[0].clone()]); let client = client_result.reference(); - let b = client.prepare_sealing(Address::default(), x!(31415926), vec![], vec![]).unwrap(); + let b = client.prepare_sealing(Address::default(), x!(31415926), vec![], vec![]).unwrap().0; assert_eq!(*b.block().header().parent_hash(), BlockView::new(&dummy_blocks[0]).header_view().sha3()); assert!(client.try_seal(b, vec![]).is_ok()); diff --git a/ethcore/src/views.rs b/ethcore/src/views.rs index 745cbff2c..11e26eb5f 100644 --- a/ethcore/src/views.rs +++ b/ethcore/src/views.rs @@ -256,6 +256,9 @@ impl<'a> HeaderView<'a> { } } + /// Returns header hash. + pub fn hash(&self) -> H256 { self.sha3() } + /// Returns raw rlp. pub fn rlp(&self) -> &Rlp<'a> { &self.rlp } diff --git a/install-parity.sh b/install-parity.sh index 439700306..74387ca7f 100755 --- a/install-parity.sh +++ b/install-parity.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -PARITY_DEB_URL=https://github.com/ethcore/parity/releases/download/beta-0.9/parity_linux_0.9.0-0_amd64.deb +PARITY_DEB_URL=https://github.com/ethcore/parity/releases/download/v1.0.0-rc1/parity_linux_1.0.0.rc1-0_amd64.deb function run_installer() diff --git a/json/Cargo.toml b/json/Cargo.toml new file mode 100644 index 000000000..7887f2cea --- /dev/null +++ b/json/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "ethjson" +version = "0.1.0" +authors = ["debris "] +build = "build.rs" + +[dependencies] +ethcore-util = { path = "../util" } +rustc-serialize = "0.3" +serde = "0.7.0" +serde_json = "0.7.0" +serde_macros = { version = "0.7.0", optional = true } +clippy = { version = "0.0.54", optional = true } + +[build-dependencies] +serde_codegen = { version = "0.7.0", optional = true } +syntex = "0.30.0" + +[features] +default = ["serde_codegen"] +nightly = ["serde_macros"] diff --git a/json/build.rs b/json/build.rs new file mode 100644 index 000000000..a23790d86 --- /dev/null +++ b/json/build.rs @@ -0,0 +1,45 @@ +// 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 . + +#[cfg(not(feature = "serde_macros"))] +mod inner { + extern crate syntex; + extern crate serde_codegen; + + use std::env; + use std::path::Path; + + pub fn main() { + let out_dir = env::var_os("OUT_DIR").unwrap(); + + let src = Path::new("src/lib.rs.in"); + let dst = Path::new(&out_dir).join("lib.rs"); + + let mut registry = syntex::Registry::new(); + + serde_codegen::register(&mut registry); + registry.expand("", &src, &dst).unwrap(); + } +} + +#[cfg(feature = "serde_macros")] +mod inner { + pub fn main() {} +} + +fn main() { + inner::main(); +} diff --git a/json/src/blockchain/account.rs b/json/src/blockchain/account.rs new file mode 100644 index 000000000..ca69409fc --- /dev/null +++ b/json/src/blockchain/account.rs @@ -0,0 +1,54 @@ +// 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 . + +//! Blockchain test account deserializer. + +use std::collections::BTreeMap; +use uint::Uint; +use bytes::Bytes; + +/// Blockchain test account deserializer. +#[derive(Debug, PartialEq, Deserialize, Clone)] +pub struct Account { + /// Balance. + pub balance: Uint, + /// Code. + pub code: Bytes, + /// Nonce. + pub nonce: Uint, + /// Storage. + pub storage: BTreeMap, +} + +#[cfg(test)] +mod tests { + use serde_json; + use blockchain::account::Account; + + #[test] + fn account_deserialization() { + let s = r#"{ + "balance" : "0x09184e72a078", + "code" : "0x600140600155", + "nonce" : "0x00", + "storage" : { + "0x01" : "0x9a10c2b5bb8f3c602e674006d9b21f09167df57c87a78a5ce96d4159ecb76520" + } + }"#; + let _deserialized: Account= serde_json::from_str(s).unwrap(); + // TODO: validate all fields + } +} diff --git a/json/src/blockchain/block.rs b/json/src/blockchain/block.rs new file mode 100644 index 000000000..03522a2c9 --- /dev/null +++ b/json/src/blockchain/block.rs @@ -0,0 +1,75 @@ +// 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 . + +//! Blockchain test block deserializer. + +use bytes::Bytes; +use blockchain::header::Header; +use blockchain::transaction::Transaction; + +/// Blockchain test block deserializer. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Block { + #[serde(rename="blockHeader")] + header: Option
, + rlp: Bytes, + transactions: Option>, + #[serde(rename="uncleHeaders")] + uncles: Option>, +} + +impl Block { + /// Returns block rlp. + pub fn rlp(&self) -> Vec { + self.rlp.clone().into() + } +} + +#[cfg(test)] +mod tests { + use serde_json; + use blockchain::block::Block; + + #[test] + fn block_deserialization() { + let s = r#"{ + "blockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "0x020000", + "extraData" : "0x", + "gasLimit" : "0x2fefba", + "gasUsed" : "0x00", + "hash" : "65ebf1b97fb89b14680267e0723d69267ec4bf9a96d4a60ffcb356ae0e81c18f", + "mixHash" : "13735ab4156c9b36327224d92e1692fab8fc362f8e0f868c94d421848ef7cd06", + "nonce" : "931dcc53e5edc514", + "number" : "0x01", + "parentHash" : "5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae", + "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "c5c83ff43741f573a0c9b31d0e56fdd745f4e37d193c4e78544f302777aafcf3", + "timestamp" : "0x56850b7b", + "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "blocknumber" : "1", + "rlp" : "0xf901fcf901f7a05a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5aea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c5c83ff43741f573a0c9b31d0e56fdd745f4e37d193c4e78544f302777aafcf3a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefba808456850b7b80a013735ab4156c9b36327224d92e1692fab8fc362f8e0f868c94d421848ef7cd0688931dcc53e5edc514c0c0", + "transactions" : [], + "uncleHeaders" : [] + }"#; + let _deserialized: Block = serde_json::from_str(s).unwrap(); + // TODO: validate all fields + } +} diff --git a/json/src/blockchain/blockchain.rs b/json/src/blockchain/blockchain.rs new file mode 100644 index 000000000..98392b983 --- /dev/null +++ b/json/src/blockchain/blockchain.rs @@ -0,0 +1,182 @@ +// 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 . + +//! Blockchain deserialization. + +use bytes::Bytes; +use hash::H256; +use blockchain::state::State; +use blockchain::header::Header; +use blockchain::block::Block; +use spec::Genesis; + +/// Blockchain deserialization. +#[derive(Debug, PartialEq, Deserialize)] +pub struct BlockChain { + /// Genesis block header. + #[serde(rename="genesisBlockHeader")] + pub genesis_block: Header, + /// Genesis block rlp. + #[serde(rename="genesisRLP")] + pub genesis_rlp: Option, + /// Blocks. + pub blocks: Vec, + /// Post state. + #[serde(rename="postState")] + pub post_state: State, + /// Pre state. + #[serde(rename="pre")] + pub pre_state: State, + /// Hash of best block. + #[serde(rename="lastblockhash")] + pub best_block: H256 +} + +impl BlockChain { + /// Returns blocks rlp. + pub fn blocks_rlp(&self) -> Vec> { + self.blocks.iter().map(|block| block.rlp()).collect() + } + + /// Returns spec compatible genesis struct. + pub fn genesis(&self) -> Genesis { + Genesis { + nonce: Some(self.genesis_block.nonce.clone()), + mix_hash: Some(self.genesis_block.mix_hash.clone()), + seal_fields: None, + seal_rlp: None, + difficulty: self.genesis_block.difficulty, + author: self.genesis_block.author.clone(), + timestamp: self.genesis_block.timestamp, + parent_hash: self.genesis_block.parent_hash.clone(), + gas_limit: self.genesis_block.gas_limit, + transactions_root: Some(self.genesis_block.transactions_root.clone()), + receipts_root: Some(self.genesis_block.receipts_root.clone()), + state_root: Some(self.genesis_block.state_root.clone()), + gas_used: Some(self.genesis_block.gas_used), + extra_data: Some(self.genesis_block.extra_data.clone()), + } + } +} + +#[cfg(test)] +mod tests { + use serde_json; + use blockchain::blockchain::BlockChain; + + #[test] + fn blockchain_deserialization() { + let s = r#"{ + "blocks" : [{ + "blockHeader" : { + "bloom" : "00000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000040000000000000000000000000000000000000000000000000000000", + "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "0x020000", + "extraData" : "0x0102030405060708091011121314151617181920212223242526272829303132", + "gasLimit" : "0x2fefba", + "gasUsed" : "0x560b", + "hash" : "06b5b1742bde29468510c92641f36b719c61b3fc3e9a21c92a23978f4f7faa2a", + "mixHash" : "5266ca43e81d25925a9ba573c3e4f9180bc076d316d90e63c6f8708b272f5ce2", + "nonce" : "59ba4daed1898e21", + "number" : "0x01", + "parentHash" : "f052d217bd5275a5177a3c3b7debdfe2670f1c8394b2965ccd5c1883cc1a524d", + "receiptTrie" : "c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296", + "stateRoot" : "bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bf", + "timestamp" : "0x56850c2c", + "transactionsTrie" : "498785da562aa0c5dd5937cf15f22139b0b1bcf3b4fc48986e1bb1dae9292796", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "rlp" : "0xf90285f90219a0f052d217bd5275a5177a3c3b7debdfe2670f1c8394b2965ccd5c1883cc1a524da01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0498785da562aa0c5dd5937cf15f22139b0b1bcf3b4fc48986e1bb1dae9292796a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fefba82560b8456850c2ca00102030405060708091011121314151617181920212223242526272829303132a05266ca43e81d25925a9ba573c3e4f9180bc076d316d90e63c6f8708b272f5ce28859ba4daed1898e21f866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ca0ee0b9ec878fbd4258a9473199d8ecc32996a20c323c004e79e0cda20e0418ce3a04e6bc63927d1510bab54f37e46fa036faf4b2c465d271920d9afea1fadf7bd21c0", + "transactions" : [ + { + "data" : "0x", + "gasLimit" : "0xc350", + "gasPrice" : "0x0a", + "nonce" : "0x00", + "r" : "0xee0b9ec878fbd4258a9473199d8ecc32996a20c323c004e79e0cda20e0418ce3", + "s" : "0x4e6bc63927d1510bab54f37e46fa036faf4b2c465d271920d9afea1fadf7bd21", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "v" : "0x1c", + "value" : "0x012a05f200" + } + ], + "uncleHeaders" : [ + ] + }], + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "0x020000", + "extraData" : "0x42", + "gasLimit" : "0x2fefd8", + "gasUsed" : "0x00", + "hash" : "f052d217bd5275a5177a3c3b7debdfe2670f1c8394b2965ccd5c1883cc1a524d", + "mixHash" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0102030405060708", + "number" : "0x00", + "parentHash" : "0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "925002c3260b44e44c3edebad1cc442142b03020209df1ab8bb86752edbd2cd7", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0925002c3260b44e44c3edebad1cc442142b03020209df1ab8bb86752edbd2cd7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421880102030405060708c0c0", + "lastblockhash" : "06b5b1742bde29468510c92641f36b719c61b3fc3e9a21c92a23978f4f7faa2a", + "postState" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "0x012a05f264", + "code" : "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600052600060206000a1", + "nonce" : "0x00", + "storage" : { + } + }, + "8888f1f195afa192cfee860698584c030f4c9db1" : { + "balance" : "0x4563918244f75c6e", + "code" : "0x", + "nonce" : "0x00", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "0x012a029592", + "code" : "0x", + "nonce" : "0x01", + "storage" : { + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "0x64", + "code" : "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600052600060206000a1", + "nonce" : "0x00", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "0x02540be400", + "code" : "0x", + "nonce" : "0x00", + "storage" : { + } + } + } + }"#; + let _deserialized: BlockChain = serde_json::from_str(s).unwrap(); + // TODO: validate all fields + //} +} diff --git a/json/src/blockchain/header.rs b/json/src/blockchain/header.rs new file mode 100644 index 000000000..ece6d6359 --- /dev/null +++ b/json/src/blockchain/header.rs @@ -0,0 +1,98 @@ +// 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 . + +//! Blockchain test header deserializer. + +use hash::{H64, Address, H256, Bloom}; +use uint::Uint; +use bytes::Bytes; + +/// Blockchain test header deserializer. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Header { + /// Blocks bloom. + pub bloom: Bloom, + /// Blocks author. + #[serde(rename="coinbase")] + pub author: Address, + /// Difficulty. + pub difficulty: Uint, + #[serde(rename="extraData")] + /// Extra data. + pub extra_data: Bytes, + /// Gas limit. + #[serde(rename="gasLimit")] + pub gas_limit: Uint, + /// Gas used. + #[serde(rename="gasUsed")] + pub gas_used: Uint, + /// Hash. + pub hash: H256, + #[serde(rename="mixHash")] + /// Mix hash. + pub mix_hash: H256, + /// Seal nonce. + pub nonce: H64, + /// Block number. + pub number: Uint, + /// Parent hash. + #[serde(rename="parentHash")] + pub parent_hash: H256, + /// Receipt root. + #[serde(rename="receiptTrie")] + pub receipts_root: H256, + /// State root. + #[serde(rename="stateRoot")] + pub state_root: H256, + /// Timestamp. + pub timestamp: Uint, + /// Transactions root. + #[serde(rename="transactionsTrie")] + pub transactions_root: H256, + /// Uncles hash. + #[serde(rename="uncleHash")] + pub uncles_hash: H256, +} + +#[cfg(test)] +mod tests { + use serde_json; + use blockchain::header::Header; + + #[test] + fn header_deserialization() { + let s = r#"{ + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "0x020000", + "extraData" : "0x", + "gasLimit" : "0x2fefba", + "gasUsed" : "0x00", + "hash" : "65ebf1b97fb89b14680267e0723d69267ec4bf9a96d4a60ffcb356ae0e81c18f", + "mixHash" : "13735ab4156c9b36327224d92e1692fab8fc362f8e0f868c94d421848ef7cd06", + "nonce" : "931dcc53e5edc514", + "number" : "0x01", + "parentHash" : "5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae", + "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "c5c83ff43741f573a0c9b31d0e56fdd745f4e37d193c4e78544f302777aafcf3", + "timestamp" : "0x56850b7b", + "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }"#; + let _deserialized: Header = serde_json::from_str(s).unwrap(); + // TODO: validate all fields + } +} diff --git a/json/src/blockchain/mod.rs b/json/src/blockchain/mod.rs new file mode 100644 index 000000000..727469ea2 --- /dev/null +++ b/json/src/blockchain/mod.rs @@ -0,0 +1,33 @@ +// 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 . + +//! Blockchain test deserialization. + +pub mod account; +pub mod block; +pub mod blockchain; +pub mod header; +pub mod state; +pub mod transaction; +pub mod test; + +pub use self::account::Account; +pub use self::block::Block; +pub use self::blockchain::BlockChain; +pub use self::header::Header; +pub use self::state::State; +pub use self::test::Test; +pub use self::transaction::Transaction; diff --git a/json/src/blockchain/state.rs b/json/src/blockchain/state.rs new file mode 100644 index 000000000..51e77e95e --- /dev/null +++ b/json/src/blockchain/state.rs @@ -0,0 +1,34 @@ +// 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 . + +//! Blockchain test state deserializer. + +use std::collections::BTreeMap; +use std::ops::Deref; +use hash::Address; +use blockchain::account::Account; + +/// Blockchain test state deserializer. +#[derive(Debug, PartialEq, Deserialize, Clone)] +pub struct State(pub BTreeMap); + +impl Deref for State { + type Target = BTreeMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/json/src/blockchain/test.rs b/json/src/blockchain/test.rs new file mode 100644 index 000000000..1a6a63a71 --- /dev/null +++ b/json/src/blockchain/test.rs @@ -0,0 +1,43 @@ +// 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 . + +//! Blockchain test deserializer. + +use std::collections::BTreeMap; +use std::ops::Deref; +use std::io::Read; +use serde_json; +use serde_json::Error; +use blockchain::blockchain::BlockChain; + +/// Blockchain test deserializer. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Test(BTreeMap); + +impl Deref for Test { + type Target = BTreeMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Test { + /// Loads test from json. + pub fn load(reader: R) -> Result where R: Read { + serde_json::from_reader(reader) + } +} diff --git a/json/src/blockchain/transaction.rs b/json/src/blockchain/transaction.rs new file mode 100644 index 000000000..5d04748f5 --- /dev/null +++ b/json/src/blockchain/transaction.rs @@ -0,0 +1,35 @@ +// 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 . + +//! Blockchain test transaction deserialization. + +use uint::Uint; +use bytes::Bytes; + +/// Blockchain test transaction deserialization. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Transaction { + data: Bytes, + #[serde(rename="gasLimit")] + gas_limit: Uint, + #[serde(rename="gasPrice")] + gas_price: Uint, + nonce: Uint, + r: Uint, + s: Uint, + v: Uint, + value: Uint +} diff --git a/json/src/bytes.rs b/json/src/bytes.rs new file mode 100644 index 000000000..6ccae51d7 --- /dev/null +++ b/json/src/bytes.rs @@ -0,0 +1,83 @@ +// 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 . + +//! Lenient bytes json deserialization for test json files. + +use rustc_serialize::hex::FromHex; +use serde::{Deserialize, Deserializer, Error}; +use serde::de::Visitor; + +/// Lenient bytes json deserialization for test json files. +#[derive(Default, Debug, PartialEq, Clone)] +pub struct Bytes(Vec); + +impl Into> for Bytes { + fn into(self) -> Vec { + self.0 + } +} + +impl Deserialize for Bytes { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer { + deserializer.deserialize(BytesVisitor) + } +} + +struct BytesVisitor; + +impl Visitor for BytesVisitor { + type Value = Bytes; + + fn visit_str(&mut self, value: &str) -> Result where E: Error { + let v = match value.len() { + 0 => vec![], + 2 if value.starts_with("0x") => vec![], + _ if value.starts_with("0x") => FromHex::from_hex(&value[2..]).unwrap_or(vec![]), + _ => FromHex::from_hex(value).unwrap_or(vec![]), + }; + Ok(Bytes(v)) + } + + fn visit_string(&mut self, value: String) -> Result where E: Error { + self.visit_str(value.as_ref()) + } +} + +#[cfg(test)] +mod test { + use serde_json; + use bytes::Bytes; + + #[test] + fn bytes_deserialization() { + let s = r#"["", "0x", "0x12", "1234"]"#; + let deserialized: Vec = serde_json::from_str(s).unwrap(); + assert_eq!(deserialized, vec![ + Bytes(vec![]), + Bytes(vec![]), + Bytes(vec![0x12]), + Bytes(vec![0x12, 0x34]) + ]); + } + + #[test] + fn bytes_into() { + let bytes = Bytes(vec![0xff, 0x11]); + let v: Vec = bytes.into(); + assert_eq!(vec![0xff, 0x11], v); + } +} diff --git a/json/src/hash.rs b/json/src/hash.rs new file mode 100644 index 000000000..c555b6266 --- /dev/null +++ b/json/src/hash.rs @@ -0,0 +1,98 @@ +// 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 . + +//! Lenient hash json deserialization for test json files. + +use std::str::FromStr; +use serde::{Deserialize, Deserializer, Error}; +use serde::de::Visitor; +use util::hash::{H64 as Hash64, Address as Hash160, H256 as Hash256, H2048 as Hash2048}; + + +macro_rules! impl_hash { + ($name: ident, $inner: ident) => { + /// Lenient hash json deserialization for test json files. + #[derive(Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Clone)] + pub struct $name($inner); + + impl Into<$inner> for $name { + fn into(self) -> $inner { + self.0 + } + } + + impl Deserialize for $name { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer { + + struct HashVisitor; + + impl Visitor for HashVisitor { + type Value = $name; + + fn visit_str(&mut self, value: &str) -> Result where E: Error { + let value = match value.len() { + 0 => $inner::from(0), + 2 if value == "0x" => $inner::from(0), + _ if value.starts_with("0x") => try!($inner::from_str(&value[2..]).map_err(|_| { + Error::custom(format!("Invalid hex value {}.", value).as_ref()) + })), + _ => try!($inner::from_str(value).map_err(|_| { + Error::custom(format!("Invalid hex value {}.", value).as_ref()) + })) + }; + + Ok($name(value)) + } + + fn visit_string(&mut self, value: String) -> Result where E: Error { + self.visit_str(value.as_ref()) + } + } + + deserializer.deserialize(HashVisitor) + } + } + } +} + +impl_hash!(H64, Hash64); +impl_hash!(Address, Hash160); +impl_hash!(H256, Hash256); +impl_hash!(Bloom, Hash2048); + +#[cfg(test)] +mod test { + use std::str::FromStr; + use serde_json; + use util::hash; + use hash::H256; + + #[test] + fn hash_deserialization() { + let s = r#"["", "5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae"]"#; + let deserialized: Vec = serde_json::from_str(s).unwrap(); + assert_eq!(deserialized, vec![ + H256(hash::H256::from(0)), + H256(hash::H256::from_str("5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae").unwrap()) + ]); + } + + #[test] + fn hash_into() { + assert_eq!(hash::H256::from(0), H256(hash::H256::from(0)).into()); + } +} diff --git a/json/src/lib.rs b/json/src/lib.rs new file mode 100644 index 000000000..b94e1fa55 --- /dev/null +++ b/json/src/lib.rs @@ -0,0 +1,28 @@ +// 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 . + +//! Json deserialization module. + +#![warn(missing_docs)] +#![cfg_attr(feature="nightly", feature(custom_derive, custom_attribute, plugin))] +#![cfg_attr(feature="nightly", plugin(serde_macros, clippy))] + +#[cfg(feature = "serde_macros")] +include!("lib.rs.in"); + +#[cfg(not(feature = "serde_macros"))] +include!(concat!(env!("OUT_DIR"), "/lib.rs")); + diff --git a/json/src/lib.rs.in b/json/src/lib.rs.in new file mode 100644 index 000000000..0d85ce569 --- /dev/null +++ b/json/src/lib.rs.in @@ -0,0 +1,26 @@ +// 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 . + +extern crate rustc_serialize; +extern crate serde; +extern crate serde_json; +extern crate ethcore_util as util; + +pub mod hash; +pub mod uint; +pub mod bytes; +pub mod blockchain; +pub mod spec; diff --git a/json/src/spec/account.rs b/json/src/spec/account.rs new file mode 100644 index 000000000..1440b1bdc --- /dev/null +++ b/json/src/spec/account.rs @@ -0,0 +1,44 @@ +// 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 . + +//! Spec account deserialization. + +use uint::Uint; +use spec::builtin::Builtin; + +/// Spec account. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Account { + builtin: Option, + balance: Option, + nonce: Option, +} + +#[cfg(test)] +mod tests { + use serde_json; + use spec::account::Account; + + #[test] + fn account_deserialization() { + let s = r#"{ + "balance": "1", + "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } + }"#; + let _deserialized: Account = serde_json::from_str(s).unwrap(); + // TODO: validate all fields + } +} diff --git a/json/src/spec/builtin.rs b/json/src/spec/builtin.rs new file mode 100644 index 000000000..21f8a2ac1 --- /dev/null +++ b/json/src/spec/builtin.rs @@ -0,0 +1,55 @@ +// 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 . + +//! Spec builtin deserialization. + +/// Linear pricing. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Linear { + base: u64, + word: u64, +} + +/// Pricing variants. +#[derive(Debug, PartialEq, Deserialize)] +pub enum Pricing { + /// Linear pricing. + #[serde(rename="linear")] + Linear(Linear), +} + +/// Spec builtin. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Builtin { + name: String, + pricing: Pricing, +} + +#[cfg(test)] +mod tests { + use serde_json; + use spec::builtin::Builtin; + + #[test] + fn builtin_deserialization() { + let s = r#"{ + "name": "ecrecover", + "pricing": { "linear": { "base": 3000, "word": 0 } } + }"#; + let _deserialized: Builtin = serde_json::from_str(s).unwrap(); + // TODO: validate all fields + } +} diff --git a/json/src/spec/genesis.rs b/json/src/spec/genesis.rs new file mode 100644 index 000000000..a2b484397 --- /dev/null +++ b/json/src/spec/genesis.rs @@ -0,0 +1,91 @@ +// 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 . + +//! Spec genesis deserialization. + +use uint::Uint; +use hash::{H64, Address, H256}; +use bytes::Bytes; + +/// Spec genesis. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Genesis { + // old seal + /// Seal nonce. + pub nonce: Option, + #[serde(rename="mixHash")] + /// Seal mix hash. + pub mix_hash: Option, + + // new seal // TODO: consider moving it to a separate seal structure + #[serde(rename="sealFields")] + /// Number of seal fields. + pub seal_fields: Option, + #[serde(rename="sealRlp")] + /// Seal rlp. + pub seal_rlp: Option, + + /// Difficulty. + pub difficulty: Uint, + /// Block author. + pub author: Address, + /// Block timestamp. + pub timestamp: Uint, + /// Parent hash. + #[serde(rename="parentHash")] + pub parent_hash: H256, + /// Gas limit. + #[serde(rename="gasLimit")] + pub gas_limit: Uint, + /// Transactions root. + #[serde(rename="transactionsRoot")] + pub transactions_root: Option, + /// Receipts root. + #[serde(rename="receiptsRoot")] + pub receipts_root: Option, + /// State root. + #[serde(rename="stateRoot")] + pub state_root: Option, + /// Gas used. + #[serde(rename="gasUsed")] + pub gas_used: Option, + /// Extra data. + #[serde(rename="extraData")] + pub extra_data: Option, +} + +#[cfg(test)] +mod tests { + use serde_json; + use spec::genesis::Genesis; + + #[test] + fn genesis_deserialization() { + let s = r#"{ + "nonce": "0x0000000000000042", + "difficulty": "0x400000000", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa", + "gasLimit": "0x1388", + "stateRoot": "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544" + }"#; + let _deserialized: Genesis = serde_json::from_str(s).unwrap(); + // TODO: validate all fields + } +} diff --git a/json/src/spec/mod.rs b/json/src/spec/mod.rs new file mode 100644 index 000000000..8783563d1 --- /dev/null +++ b/json/src/spec/mod.rs @@ -0,0 +1,29 @@ +// 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 . + +//! Spec deserialization. + +pub mod account; +pub mod builtin; +pub mod genesis; +pub mod params; +pub mod spec; + +pub use self::account::Account; +pub use self::builtin::Builtin; +pub use self::genesis::Genesis; +pub use self::params::Params; +pub use self::spec::Spec; diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs new file mode 100644 index 000000000..e55f7fc48 --- /dev/null +++ b/json/src/spec/params.rs @@ -0,0 +1,74 @@ +// 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 . + +//! Spec params deserialization. + +use uint::Uint; +use hash::Address; + +/// Spec params. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Params { + #[serde(rename="accountStartNonce")] + account_start_nonce: Uint, + #[serde(rename="frontierCompatibilityModeLimit")] + frontier_compatibility_mode_limit: Uint, + #[serde(rename="maximumExtraDataSize")] + maximum_extra_data_size: Uint, + #[serde(rename="tieBreakingGas")] + tie_breaking_gas: bool, + #[serde(rename="minGasLimit")] + min_gas_limit: Uint, + #[serde(rename="gasLimitBoundDivisor")] + gas_limit_bound_divisor: Uint, + #[serde(rename="minimumDifficulty")] + minimum_difficulty: Uint, + #[serde(rename="difficultyBoundDivisor")] + difficulty_bound_divisor: Uint, + #[serde(rename="durationLimit")] + duration_limit: Uint, + #[serde(rename="blockReward")] + block_reward: Uint, + registrar: Address, + #[serde(rename="networkID")] + network_id: Uint, +} + +#[cfg(test)] +mod tests { + use serde_json; + use spec::params::Params; + + #[test] + fn params_deserialization() { + let s = r#"{ + "accountStartNonce": "0x00", + "frontierCompatibilityModeLimit": "0x118c30", + "maximumExtraDataSize": "0x20", + "tieBreakingGas": false, + "minGasLimit": "0x1388", + "gasLimitBoundDivisor": "0x0400", + "minimumDifficulty": "0x020000", + "difficultyBoundDivisor": "0x0800", + "durationLimit": "0x0d", + "blockReward": "0x4563918244F40000", + "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", + "networkID" : "0x1" + }"#; + let _deserialized: Params = serde_json::from_str(s).unwrap(); + // TODO: validate all fields + } +} diff --git a/json/src/spec/spec.rs b/json/src/spec/spec.rs new file mode 100644 index 000000000..2dd4ac486 --- /dev/null +++ b/json/src/spec/spec.rs @@ -0,0 +1,84 @@ +// 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 . + +//! Spec deserialization. + +use std::collections::BTreeMap; +use hash::Address; +use spec::account::Account; +use spec::params::Params; +use spec::genesis::Genesis; + +/// Spec deserialization. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Spec { + name: String, + #[serde(rename="engineName")] + engine_name: String, // TODO: consider making it an enum + params: Params, + genesis: Genesis, + accounts: BTreeMap, +} + +#[cfg(test)] +mod tests { + use serde_json; + use spec::spec::Spec; + + #[test] + fn spec_deserialization() { + let s = r#"{ + "name": "Morden", + "engineName": "Ethash", + "params": { + "accountStartNonce": "0x0100000", + "frontierCompatibilityModeLimit": "0x789b0", + "maximumExtraDataSize": "0x20", + "tieBreakingGas": false, + "minGasLimit": "0x1388", + "gasLimitBoundDivisor": "0x0400", + "minimumDifficulty": "0x020000", + "difficultyBoundDivisor": "0x0800", + "durationLimit": "0x0d", + "blockReward": "0x4563918244F40000", + "registrar": "", + "networkID" : "0x2" + }, + "genesis": { + "nonce": "0x00006d6f7264656e", + "difficulty": "0x20000", + "mixHash": "0x00000000000000000000000000000000000000647572616c65787365646c6578", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x2fefd8" + }, + "nodes": [ + "enode://b1217cbaa440e35ed471157123fe468e19e8b5ad5bedb4b1fdbcbdab6fb2f5ed3e95dd9c24a22a79fdb2352204cea207df27d92bfd21bfd41545e8b16f637499@104.44.138.37:30303" + ], + "accounts": { + "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" } + } + }"#; + let _deserialized: Spec = serde_json::from_str(s).unwrap(); + // TODO: validate all fields + } +} diff --git a/json/src/uint.rs b/json/src/uint.rs new file mode 100644 index 000000000..f6eae80e4 --- /dev/null +++ b/json/src/uint.rs @@ -0,0 +1,94 @@ +// 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 . + +//! Lenient uint json deserialization for test json files. + +use std::str::FromStr; +use serde::{Deserialize, Deserializer, Error}; +use serde::de::Visitor; +use util::numbers::{U256, Uint as U}; + +/// Lenient uint json deserialization for test json files. +#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] +pub struct Uint(U256); + +impl Into for Uint { + fn into(self) -> U256 { + self.0 + } +} + +impl Into for Uint { + fn into(self) -> u64 { + u64::from(self.0) + } +} + +impl Deserialize for Uint { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer { + deserializer.deserialize(UintVisitor) + } +} + +struct UintVisitor; + +impl Visitor for UintVisitor { + type Value = Uint; + + fn visit_str(&mut self, value: &str) -> Result where E: Error { + let value = match value.len() { + 0 => U256::from(0), + 2 if value.starts_with("0x") => U256::from(0), + _ if value.starts_with("0x") => try!(U256::from_str(&value[2..]).map_err(|_| { + Error::custom(format!("Invalid hex value {}.", value).as_ref()) + })), + _ => try!(U256::from_dec_str(value).map_err(|_| { + Error::custom(format!("Invalid decimal value {}.", value).as_ref()) + })) + }; + + Ok(Uint(value)) + } + + fn visit_string(&mut self, value: String) -> Result where E: Error { + self.visit_str(value.as_ref()) + } +} + +#[cfg(test)] +mod test { + use serde_json; + use util::numbers::U256; + use uint::Uint; + + #[test] + fn uint_deserialization() { + let s = r#"["0xa", "10", "", "0x"]"#; + let deserialized: Vec = serde_json::from_str(s).unwrap(); + assert_eq!(deserialized, vec![ + Uint(U256::from(10)), + Uint(U256::from(10)), + Uint(U256::from(0)), + Uint(U256::from(0)) + ]); + } + + #[test] + fn uint_into() { + assert_eq!(U256::from(10), Uint(U256::from(10)).into()); + } +} diff --git a/miner/Cargo.toml b/miner/Cargo.toml index 1cee23457..1afa79bae 100644 --- a/miner/Cargo.toml +++ b/miner/Cargo.toml @@ -17,7 +17,7 @@ log = "0.3" env_logger = "0.3" rustc-serialize = "0.3" rayon = "0.3.1" -clippy = { version = "0.0.50", optional = true } +clippy = { version = "0.0.54", optional = true } [features] default = [] diff --git a/miner/src/lib.rs b/miner/src/lib.rs index a431bd44e..ca25e3993 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -42,10 +42,9 @@ //! //! let miner: Miner = Miner::default(); //! // get status -//! assert_eq!(miner.status().transaction_queue_pending, 0); +//! assert_eq!(miner.status().transactions_in_pending_queue, 0); //! //! // Check block for sealing -//! miner.prepare_sealing(client.deref()); //! assert!(miner.sealing_block(client.deref()).lock().unwrap().is_some()); //! } //! ``` @@ -62,11 +61,11 @@ extern crate rayon; mod miner; mod transaction_queue; -pub use transaction_queue::TransactionQueue; +pub use transaction_queue::{TransactionQueue, AccountDetails}; pub use miner::{Miner}; use std::sync::Mutex; -use util::{H256, U256, Address, Bytes}; +use util::{H256, Address, Bytes}; use ethcore::client::{BlockChainClient}; use ethcore::block::{ClosedBlock}; use ethcore::error::{Error}; @@ -79,8 +78,8 @@ pub trait MinerService : Send + Sync { fn status(&self) -> MinerStatus; /// Imports transactions to transaction queue. - fn import_transactions(&self, transactions: Vec, fetch_nonce: T) -> Result<(), Error> - where T: Fn(&Address) -> U256; + fn import_transactions(&self, transactions: Vec, fetch_account: T) -> Vec> + where T: Fn(&Address) -> AccountDetails; /// Returns hashes of transactions currently in pending fn pending_transactions_hashes(&self) -> Vec; @@ -92,7 +91,7 @@ pub trait MinerService : Send + Sync { fn chain_new_blocks(&self, chain: &BlockChainClient, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]); /// New chain head event. Restart mining operation. - fn prepare_sealing(&self, chain: &BlockChainClient); + fn update_sealing(&self, chain: &BlockChainClient); /// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock. fn sealing_block(&self, chain: &BlockChainClient) -> &Mutex>; @@ -105,7 +104,9 @@ pub trait MinerService : Send + Sync { /// Mining status pub struct MinerStatus { /// Number of transactions in queue with state `pending` (ready to be included in block) - pub transaction_queue_pending: usize, + pub transactions_in_pending_queue: usize, /// Number of transactions in queue with state `future` (not yet ready to be included in block) - pub transaction_queue_future: usize, + pub transactions_in_future_queue: usize, + /// Number of transactions included in currently mined block + pub transactions_in_pending_block: usize, } diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 6d5b3086e..e1b314d57 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -18,14 +18,15 @@ use rayon::prelude::*; use std::sync::{Mutex, RwLock, Arc}; use std::sync::atomic; use std::sync::atomic::AtomicBool; +use std::collections::HashSet; use util::{H256, U256, Address, Bytes, Uint}; -use ethcore::views::{BlockView}; +use ethcore::views::{BlockView, HeaderView}; use ethcore::client::{BlockChainClient, BlockId}; -use ethcore::block::{ClosedBlock}; +use ethcore::block::{ClosedBlock, IsBlock}; use ethcore::error::{Error}; use ethcore::transaction::SignedTransaction; -use super::{MinerService, MinerStatus, TransactionQueue}; +use super::{MinerService, MinerStatus, TransactionQueue, AccountDetails}; /// Keeps track of transactions using priority queue and holds currently mined block. pub struct Miner { @@ -33,6 +34,7 @@ pub struct Miner { // for sealing... sealing_enabled: AtomicBool, + sealing_block_last_request: Mutex, sealing_block: Mutex>, gas_floor_target: RwLock, author: RwLock
, @@ -45,6 +47,7 @@ impl Default for Miner { Miner { transaction_queue: Mutex::new(TransactionQueue::new()), sealing_enabled: AtomicBool::new(false), + sealing_block_last_request: Mutex::new(0), sealing_block: Mutex::new(None), gas_floor_target: RwLock::new(U256::zero()), author: RwLock::new(Address::default()), @@ -71,7 +74,7 @@ impl Miner { /// Get the extra_data that we will seal blocks wuth. fn gas_floor_target(&self) -> U256 { - self.gas_floor_target.read().unwrap().clone() + *self.gas_floor_target.read().unwrap() } /// Set the author that we will seal blocks as. @@ -93,27 +96,60 @@ impl Miner { pub fn set_minimal_gas_price(&self, min_gas_price: U256) { self.transaction_queue.lock().unwrap().set_minimal_gas_price(min_gas_price); } + + /// Prepares new block for sealing including top transactions from queue. + fn prepare_sealing(&self, chain: &BlockChainClient) { + let transactions = self.transaction_queue.lock().unwrap().top_transactions(); + let b = chain.prepare_sealing( + self.author(), + self.gas_floor_target(), + self.extra_data(), + transactions, + ); + + *self.sealing_block.lock().unwrap() = b.map(|(block, invalid_transactions)| { + let mut queue = self.transaction_queue.lock().unwrap(); + queue.remove_all( + &invalid_transactions.into_iter().collect::>(), + |a: &Address| AccountDetails { + nonce: chain.nonce(a), + balance: chain.balance(a), + } + ); + block + }); + } + + fn update_gas_limit(&self, chain: &BlockChainClient) { + let gas_limit = HeaderView::new(&chain.best_block_header()).gas_limit(); + let mut queue = self.transaction_queue.lock().unwrap(); + queue.set_gas_limit(gas_limit); + } } +const SEALING_TIMEOUT_IN_BLOCKS : u64 = 5; + impl MinerService for Miner { fn clear_and_reset(&self, chain: &BlockChainClient) { self.transaction_queue.lock().unwrap().clear(); - self.prepare_sealing(chain); + self.update_sealing(chain); } fn status(&self) -> MinerStatus { let status = self.transaction_queue.lock().unwrap().status(); + let block = self.sealing_block.lock().unwrap(); MinerStatus { - transaction_queue_pending: status.pending, - transaction_queue_future: status.future, + transactions_in_pending_queue: status.pending, + transactions_in_future_queue: status.future, + transactions_in_pending_block: block.as_ref().map_or(0, |b| b.transactions().len()), } } - fn import_transactions(&self, transactions: Vec, fetch_nonce: T) -> Result<(), Error> - where T: Fn(&Address) -> U256 { + fn import_transactions(&self, transactions: Vec, fetch_account: T) -> Vec> + where T: Fn(&Address) -> AccountDetails { let mut transaction_queue = self.transaction_queue.lock().unwrap(); - transaction_queue.add_all(transactions, fetch_nonce) + transaction_queue.add_all(transactions, fetch_account) } fn pending_transactions_hashes(&self) -> Vec { @@ -121,26 +157,29 @@ impl MinerService for Miner { transaction_queue.pending_hashes() } - fn prepare_sealing(&self, chain: &BlockChainClient) { - let no_of_transactions = 128; - // TODO: should select transactions orm queue according to gas limit of block. - let transactions = self.transaction_queue.lock().unwrap().top_transactions(no_of_transactions); + fn update_sealing(&self, chain: &BlockChainClient) { + let should_disable_sealing = { + let current_no = chain.chain_info().best_block_number; + let last_request = self.sealing_block_last_request.lock().unwrap(); + let is_greater = current_no > *last_request; + is_greater && current_no - *last_request > SEALING_TIMEOUT_IN_BLOCKS + }; - let b = chain.prepare_sealing( - self.author(), - self.gas_floor_target(), - self.extra_data(), - transactions, - ); - *self.sealing_block.lock().unwrap() = b; + if should_disable_sealing { + self.sealing_enabled.store(false, atomic::Ordering::Relaxed); + *self.sealing_block.lock().unwrap() = None; + } else if self.sealing_enabled.load(atomic::Ordering::Relaxed) { + self.prepare_sealing(chain); + } } fn sealing_block(&self, chain: &BlockChainClient) -> &Mutex> { if self.sealing_block.lock().unwrap().is_none() { self.sealing_enabled.store(true, atomic::Ordering::Relaxed); - // TODO: Above should be on a timer that resets after two blocks have arrived without being asked for. + self.prepare_sealing(chain); } + *self.sealing_block_last_request.lock().unwrap() = chain.chain_info().best_block_number; &self.sealing_block } @@ -175,32 +214,92 @@ impl MinerService for Miner { block.transactions() } + // First update gas limit in transaction queue + self.update_gas_limit(chain); + + // Then import all transactions... { - let in_chain = vec![imported, enacted, invalid]; - let in_chain = in_chain - .par_iter() - .flat_map(|h| h.par_iter().map(|h| fetch_transactions(chain, h))); let out_of_chain = retracted .par_iter() .map(|h| fetch_transactions(chain, h)); - - in_chain.for_each(|txs| { - let mut transaction_queue = self.transaction_queue.lock().unwrap(); - let hashes = txs.iter().map(|tx| tx.hash()).collect::>(); - transaction_queue.remove_all(&hashes, |a| chain.nonce(a)); - }); out_of_chain.for_each(|txs| { // populate sender for tx in &txs { let _sender = tx.sender(); } let mut transaction_queue = self.transaction_queue.lock().unwrap(); - let _ = transaction_queue.add_all(txs, |a| chain.nonce(a)); + let _ = transaction_queue.add_all(txs, |a| AccountDetails { + nonce: chain.nonce(a), + balance: chain.balance(a) + }); }); } - if self.sealing_enabled.load(atomic::Ordering::Relaxed) { - self.prepare_sealing(chain); + // ...and after that remove old ones + { + let in_chain = { + let mut in_chain = HashSet::new(); + in_chain.extend(imported); + in_chain.extend(enacted); + in_chain.extend(invalid); + in_chain + .into_iter() + .collect::>() + }; + + let in_chain = in_chain + .par_iter() + .map(|h: &H256| fetch_transactions(chain, h)); + + in_chain.for_each(|txs| { + let hashes = txs.iter().map(|tx| tx.hash()).collect::>(); + let mut transaction_queue = self.transaction_queue.lock().unwrap(); + transaction_queue.remove_all(&hashes, |a| AccountDetails { + nonce: chain.nonce(a), + balance: chain.balance(a) + }); + }); } + + self.update_sealing(chain); + } +} + +#[cfg(test)] +mod tests { + + use MinerService; + use super::{Miner}; + use ethcore::client::{TestBlockChainClient, EachBlockWith}; + + // TODO [ToDr] To uncomment client is cleaned from mining stuff. + #[ignore] + #[test] + fn should_prepare_block_to_seal() { + // given + let client = TestBlockChainClient::default(); + let miner = Miner::default(); + + // when + let res = miner.sealing_block(&client); + + // then + assert!(res.lock().unwrap().is_some(), "Expected closed block"); + } + + #[test] + fn should_reset_seal_after_couple_of_blocks() { + // given + let client = TestBlockChainClient::default(); + let miner = Miner::default(); + let res = miner.sealing_block(&client); + // TODO [ToDr] Uncomment after fixing TestBlockChainClient + // assert!(res.lock().unwrap().is_some(), "Expected closed block"); + + // when + client.add_blocks(10, EachBlockWith::Uncle); + + // then + assert!(res.lock().unwrap().is_none(), "Expected to remove sealed block"); } } diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index 324a46364..4b76fcbb2 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -34,7 +34,7 @@ //! use util::crypto::KeyPair; //! use util::hash::Address; //! use util::numbers::{Uint, U256}; -//! use ethminer::TransactionQueue; +//! use ethminer::{TransactionQueue, AccountDetails}; //! use ethcore::transaction::*; //! use rustc_serialize::hex::FromHex; //! @@ -47,16 +47,19 @@ //! //! let st1 = t1.sign(&key.secret()); //! let st2 = t2.sign(&key.secret()); -//! let default_nonce = |_a: &Address| U256::from(10); +//! let default_nonce = |_a: &Address| AccountDetails { +//! nonce: U256::from(10), +//! balance: U256::from(1_000_000), +//! }; //! //! let mut txq = TransactionQueue::new(); -//! txq.add(st2.clone(), &default_nonce); -//! txq.add(st1.clone(), &default_nonce); +//! txq.add(st2.clone(), &default_nonce).unwrap(); +//! txq.add(st1.clone(), &default_nonce).unwrap(); //! //! // Check status //! assert_eq!(txq.status().pending, 2); //! // Check top transactions -//! let top = txq.top_transactions(3); +//! let top = txq.top_transactions(); //! assert_eq!(top.len(), 2); //! assert_eq!(top[0], st1); //! assert_eq!(top[1], st2); @@ -66,7 +69,7 @@ //! txq.remove(&st1.hash(), &default_nonce); //! assert_eq!(txq.status().pending, 0); //! assert_eq!(txq.status().future, 1); -//! assert_eq!(txq.top_transactions(3).len(), 0); +//! assert_eq!(txq.top_transactions().len(), 0); //! } //! ``` //! @@ -232,8 +235,6 @@ impl TransactionSet { } } -// Will be used when rpc merged -#[allow(dead_code)] #[derive(Debug)] /// Current status of the queue pub struct TransactionQueueStatus { @@ -243,10 +244,24 @@ pub struct TransactionQueueStatus { pub future: usize, } +/// Details of account +pub struct AccountDetails { + /// Most recent account nonce + pub nonce: U256, + /// Current account balance + pub balance: U256, +} + + +/// Transactions with `gas > (gas_limit + gas_limit * Factor(in percents))` are not imported to the queue. +const GAS_LIMIT_HYSTERESIS: usize = 10; // % + /// TransactionQueue implementation pub struct TransactionQueue { /// Gas Price threshold for transactions that can be imported to this queue (defaults to 0) minimal_gas_price: U256, + /// Current gas limit (block gas limit * factor). Transactions above the limit will not be accepted (default to !0) + gas_limit: U256, /// Priority queue for transactions that can go to block current: TransactionSet, /// Priority queue for transactions that has been received but are not yet valid to go to block @@ -284,6 +299,7 @@ impl TransactionQueue { TransactionQueue { minimal_gas_price: U256::zero(), + gas_limit: !U256::zero(), current: current, future: future, by_hash: HashMap::new(), @@ -292,11 +308,22 @@ impl TransactionQueue { } /// Sets new gas price threshold for incoming transactions. - /// Any transactions already imported to the queue are not affected. + /// Any transaction already imported to the queue is not affected. pub fn set_minimal_gas_price(&mut self, min_gas_price: U256) { self.minimal_gas_price = min_gas_price; } + /// Sets new gas limit. Transactions with gas slightly (`GAS_LIMIT_HYSTERESIS`) above the limit won't be imported. + /// Any transaction already imported to the queue is not affected. + pub fn set_gas_limit(&mut self, gas_limit: U256) { + let extra = gas_limit / U256::from(GAS_LIMIT_HYSTERESIS); + + self.gas_limit = match gas_limit.overflowing_add(extra) { + (_, true) => !U256::zero(), + (val, false) => val, + }; + } + // Will be used when rpc merged #[allow(dead_code)] /// Returns current status for this queue @@ -308,49 +335,77 @@ impl TransactionQueue { } /// Adds all signed transactions to queue to be verified and imported - pub fn add_all(&mut self, txs: Vec, fetch_nonce: T) -> Result<(), Error> - where T: Fn(&Address) -> U256 { - for tx in txs.into_iter() { - try!(self.add(tx, &fetch_nonce)); - } - Ok(()) + pub fn add_all(&mut self, txs: Vec, fetch_account: T) -> Vec> + where T: Fn(&Address) -> AccountDetails { + + txs.into_iter() + .map(|tx| self.add(tx, &fetch_account)) + .collect() } /// Add signed transaction to queue to be verified and imported - pub fn add(&mut self, tx: SignedTransaction, fetch_nonce: &T) -> Result<(), Error> - where T: Fn(&Address) -> U256 { + pub fn add(&mut self, tx: SignedTransaction, fetch_account: &T) -> Result<(), Error> + where T: Fn(&Address) -> AccountDetails { + + trace!(target: "miner", "Importing: {:?}", tx.hash()); if tx.gas_price < self.minimal_gas_price { - trace!(target: "sync", + trace!(target: "miner", "Dropping transaction below minimal gas price threshold: {:?} (gp: {} < {})", tx.hash(), tx.gas_price, self.minimal_gas_price ); - return Err(Error::Transaction(TransactionError::InsufficientGasPrice{ + return Err(Error::Transaction(TransactionError::InsufficientGasPrice { minimal: self.minimal_gas_price, - got: tx.gas_price + got: tx.gas_price, })); } - self.import_tx(try!(VerifiedTransaction::new(tx)), fetch_nonce); - Ok(()) + if tx.gas > self.gas_limit { + trace!(target: "miner", + "Dropping transaction above gas limit: {:?} ({} > {})", + tx.hash(), tx.gas, self.gas_limit + ); + + return Err(Error::Transaction(TransactionError::GasLimitExceeded { + limit: self.gas_limit, + got: tx.gas, + })); + } + + + let vtx = try!(VerifiedTransaction::new(tx)); + let account = fetch_account(&vtx.sender()); + + let cost = vtx.transaction.value + vtx.transaction.gas_price * vtx.transaction.gas; + if account.balance < cost { + trace!(target: "miner", "Dropping transaction without sufficient balance: {:?} ({} < {})", + vtx.hash(), account.balance, cost); + return Err(Error::Transaction(TransactionError::InsufficientBalance { + cost: cost, + balance: account.balance + })); + } + + self.import_tx(vtx, account.nonce).map_err(Error::Transaction) } /// Removes all transactions identified by hashes given in slice /// /// If gap is introduced marks subsequent transactions as future - pub fn remove_all(&mut self, transaction_hashes: &[H256], fetch_nonce: T) - where T: Fn(&Address) -> U256 { + pub fn remove_all(&mut self, transaction_hashes: &[H256], fetch_account: T) + where T: Fn(&Address) -> AccountDetails { for hash in transaction_hashes { - self.remove(&hash, &fetch_nonce); + self.remove(&hash, &fetch_account); } } /// Removes transaction identified by hashes from queue. /// /// If gap is introduced marks subsequent transactions as future - pub fn remove(&mut self, transaction_hash: &H256, fetch_nonce: &T) - where T: Fn(&Address) -> U256 { + pub fn remove(&mut self, transaction_hash: &H256, fetch_account: &T) + where T: Fn(&Address) -> AccountDetails { + let transaction = self.by_hash.remove(transaction_hash); if transaction.is_none() { // We don't know this transaction @@ -360,7 +415,8 @@ impl TransactionQueue { let transaction = transaction.unwrap(); let sender = transaction.sender(); let nonce = transaction.nonce(); - let current_nonce = fetch_nonce(&sender); + let current_nonce = fetch_account(&sender).nonce; + // Remove from future let order = self.future.drop(&sender, &nonce); @@ -401,6 +457,7 @@ impl TransactionQueue { if k >= current_nonce { self.future.insert(*sender, k, order.update_height(k, current_nonce)); } else { + trace!(target: "miner", "Dropping old transaction: {:?} (nonce: {} < {})", order.hash, k, current_nonce); // Remove the transaction completely self.by_hash.remove(&order.hash); } @@ -421,19 +478,17 @@ impl TransactionQueue { if k >= current_nonce { self.future.insert(*sender, k, order.update_height(k, current_nonce)); } else { + trace!(target: "miner", "Dropping old transaction: {:?} (nonce: {} < {})", order.hash, k, current_nonce); self.by_hash.remove(&order.hash); } } self.future.enforce_limit(&mut self.by_hash); } - // Will be used when mining merged - #[allow(dead_code)] /// Returns top transactions from the queue ordered by priority. - pub fn top_transactions(&self, size: usize) -> Vec { + pub fn top_transactions(&self) -> Vec { self.current.by_priority .iter() - .take(size) .map(|t| self.by_hash.get(&t.hash).expect("Transaction Queue Inconsistency")) .map(|t| t.transaction.clone()) .collect() @@ -486,19 +541,20 @@ impl TransactionQueue { /// /// It ignores transactions that has already been imported (same `hash`) and replaces the transaction /// iff `(address, nonce)` is the same but `gas_price` is higher. - fn import_tx(&mut self, tx: VerifiedTransaction, fetch_nonce: &T) - where T: Fn(&Address) -> U256 { + /// + /// Returns `true` when transaction was imported successfuly + fn import_tx(&mut self, tx: VerifiedTransaction, state_nonce: U256) -> Result<(), TransactionError> { if self.by_hash.get(&tx.hash()).is_some() { // Transaction is already imported. - trace!(target: "sync", "Dropping already imported transaction with hash: {:?}", tx.hash()); - return; + trace!(target: "miner", "Dropping already imported transaction: {:?}", tx.hash()); + return Err(TransactionError::AlreadyImported); } + let address = tx.sender(); let nonce = tx.nonce(); - let state_nonce = fetch_nonce(&address); let next_nonce = self.last_nonces .get(&address) .cloned() @@ -509,11 +565,11 @@ impl TransactionQueue { // We have a gap - put to future Self::replace_transaction(tx, next_nonce, &mut self.future, &mut self.by_hash); self.future.enforce_limit(&mut self.by_hash); - return; + return Ok(()); } else if nonce < state_nonce { // Droping transaction - trace!(target: "sync", "Dropping transaction with nonce: {} - expecting: {}", nonce, next_nonce); - return; + trace!(target: "miner", "Dropping old transaction: {:?} (nonce: {} < {})", tx.hash(), nonce, next_nonce); + return Err(TransactionError::Old); } Self::replace_transaction(tx, state_nonce, &mut self.current, &mut self.by_hash); @@ -521,6 +577,9 @@ impl TransactionQueue { // But maybe there are some more items waiting in future? self.move_matching_future_to_current(address, nonce + U256::one(), state_nonce); self.current.enforce_limit(&mut self.by_hash); + + trace!(target: "miner", "status: {:?}", self.status()); + Ok(()) } /// Replaces transaction in given set (could be `future` or `current`). @@ -579,8 +638,11 @@ mod test { new_unsigned_tx(U256::from(123)).sign(&keypair.secret()) } - fn default_nonce(_address: &Address) -> U256 { - U256::from(123) + fn default_nonce(_address: &Address) -> AccountDetails { + AccountDetails { + nonce: U256::from(123), + balance: !U256::zero() + } } fn new_txs(second_nonce: U256) -> (SignedTransaction, SignedTransaction) { @@ -649,6 +711,56 @@ mod test { assert_eq!(stats.pending, 1); } + #[test] + fn gas_limit_should_never_overflow() { + // given + let mut txq = TransactionQueue::new(); + txq.set_gas_limit(U256::zero()); + assert_eq!(txq.gas_limit, U256::zero()); + + // when + txq.set_gas_limit(!U256::zero()); + + // then + assert_eq!(txq.gas_limit, !U256::zero()); + } + + #[test] + fn should_not_import_transaction_above_gas_limit() { + // given + let mut txq = TransactionQueue::new(); + let tx = new_tx(); + txq.set_gas_limit(tx.gas / U256::from(2)); + + // when + txq.add(tx, &default_nonce).unwrap_err(); + + // then + let stats = txq.status(); + assert_eq!(stats.pending, 0); + assert_eq!(stats.future, 0); + } + + + #[test] + fn should_drop_transactions_from_senders_without_balance() { + // given + let mut txq = TransactionQueue::new(); + let tx = new_tx(); + let account = |a: &Address| AccountDetails { + nonce: default_nonce(a).nonce, + balance: U256::one() + }; + + // when + txq.add(tx, &account).unwrap_err(); + + // then + let stats = txq.status(); + assert_eq!(stats.pending, 0); + assert_eq!(stats.future, 0); + } + #[test] fn should_not_import_transaction_below_min_gas_price_threshold() { // given @@ -702,7 +814,7 @@ mod test { txq.add(tx2.clone(), &default_nonce).unwrap(); // then - let top = txq.top_transactions(5); + let top = txq.top_transactions(); assert_eq!(top[0], tx); assert_eq!(top[1], tx2); assert_eq!(top.len(), 2); @@ -741,7 +853,7 @@ mod test { let stats = txq.status(); assert_eq!(stats.pending, 1); assert_eq!(stats.future, 1); - let top = txq.top_transactions(5); + let top = txq.top_transactions(); assert_eq!(top.len(), 1); assert_eq!(top[0], tx); } @@ -749,8 +861,10 @@ mod test { #[test] fn should_correctly_update_futures_when_removing() { // given - let prev_nonce = |a: &Address| default_nonce(a) - U256::one(); - let next2_nonce = |a: &Address| default_nonce(a) + U256::from(2); + let prev_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce - U256::one(), balance: + !U256::zero() }; + let next2_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce + U256::from(2), balance: + !U256::zero() }; let mut txq = TransactionQueue::new(); @@ -866,7 +980,7 @@ mod test { txq.add(tx2.clone(), &default_nonce).unwrap(); // then - let t = txq.top_transactions(2); + let t = txq.top_transactions(); assert_eq!(txq.status().pending, 1); assert_eq!(t.len(), 1); assert_eq!(t[0], tx); @@ -895,10 +1009,10 @@ mod test { let mut txq = TransactionQueue::new(); let tx = new_tx(); let last_nonce = tx.nonce + U256::one(); - let fetch_last_nonce = |_a: &Address| last_nonce; + let fetch_last_nonce = |_a: &Address| AccountDetails{ nonce: last_nonce, balance: !U256::zero() }; // when - txq.add(tx, &fetch_last_nonce).unwrap(); + txq.add(tx, &fetch_last_nonce).unwrap_err(); // then let stats = txq.status(); @@ -909,7 +1023,8 @@ mod test { #[test] fn should_not_insert_same_transaction_twice() { // given - let nonce = |a: &Address| default_nonce(a) + U256::one(); + let nonce = |a: &Address| AccountDetails { nonce: default_nonce(a).nonce + U256::one(), + balance: !U256::zero() }; let mut txq = TransactionQueue::new(); let (_tx1, tx2) = new_txs(U256::from(1)); txq.add(tx2.clone(), &default_nonce).unwrap(); @@ -917,7 +1032,7 @@ mod test { assert_eq!(txq.status().pending, 0); // when - txq.add(tx2.clone(), &nonce).unwrap(); + txq.add(tx2.clone(), &nonce).unwrap_err(); // then let stats = txq.status(); @@ -949,7 +1064,8 @@ mod test { #[test] fn should_not_move_to_future_if_state_nonce_is_higher() { // given - let next_nonce = |a: &Address| default_nonce(a) + U256::one(); + let next_nonce = |a: &Address| AccountDetails { nonce: default_nonce(a).nonce + U256::one(), balance: + !U256::zero() }; let mut txq = TransactionQueue::new(); let (tx, tx2) = new_txs(U256::from(1)); let tx3 = new_tx(); @@ -988,7 +1104,7 @@ mod test { let stats = txq.status(); assert_eq!(stats.pending, 1); assert_eq!(stats.future, 0); - assert_eq!(txq.top_transactions(1)[0].gas_price, U256::from(200)); + assert_eq!(txq.top_transactions()[0].gas_price, U256::from(200)); } #[test] @@ -1018,14 +1134,16 @@ mod test { let stats = txq.status(); assert_eq!(stats.future, 0); assert_eq!(stats.pending, 2); - assert_eq!(txq.top_transactions(2)[1].gas_price, U256::from(200)); + assert_eq!(txq.top_transactions()[1].gas_price, U256::from(200)); } #[test] fn should_recalculate_height_when_removing_from_future() { // given - let previous_nonce = |a: &Address| default_nonce(a) - U256::one(); - let next_nonce = |a: &Address| default_nonce(a) + U256::one(); + let previous_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce - U256::one(), balance: + !U256::zero() }; + let next_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce + U256::one(), balance: + !U256::zero() }; let mut txq = TransactionQueue::new(); let (tx1, tx2) = new_txs(U256::one()); txq.add(tx1.clone(), &previous_nonce).unwrap(); diff --git a/parity/main.rs b/parity/main.rs index b8cc2a0f0..e029124c4 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -46,6 +46,7 @@ use env_logger::LogBuilder; use ctrlc::CtrlC; use util::*; use util::panics::{MayPanic, ForwardPanic, PanicHandler}; +use util::keys::store::*; use ethcore::spec::*; use ethcore::client::*; use ethcore::service::{ClientService, NetSyncMessage}; @@ -55,7 +56,6 @@ use ethminer::{Miner, MinerService}; use docopt::Docopt; use daemonize::Daemonize; use number_prefix::{binary_prefix, Standalone, Prefixed}; -use util::keys::store::*; fn die_with_message(msg: &str) -> ! { println!("ERROR: {}", msg); @@ -105,8 +105,9 @@ Networking Options: API and Console Options: -j --jsonrpc Enable the JSON-RPC API sever. - --jsonrpc-addr HOST Specify the hostname portion of the JSONRPC API - server [default: 127.0.0.1]. + --jsonrpc-interface IP Specify the hostname portion of the JSONRPC API + server, IP should be an interface's IP address, or + all (all interfaces) or local [default: local]. --jsonrpc-port PORT Specify the port portion of the JSONRPC API server [default: 8545]. --jsonrpc-cors URL Specify CORS header for JSON-RPC API responses @@ -149,7 +150,7 @@ Geth-compatibility Options: --nodekey KEY Equivalent to --node-key KEY. --nodiscover Equivalent to --no-discovery. --rpc Equivalent to --jsonrpc. - --rpcaddr HOST Equivalent to --jsonrpc-addr HOST. + --rpcaddr IP Equivalent to --jsonrpc-interface IP. --rpcport PORT Equivalent to --jsonrpc-port PORT. --rpcapi APIS Equivalent to --jsonrpc-apis APIS. --rpccorsdomain URL Equivalent to --jsonrpc-cors URL. @@ -188,7 +189,7 @@ struct Args { flag_cache_max_size: usize, flag_queue_max_size: usize, flag_jsonrpc: bool, - flag_jsonrpc_addr: String, + flag_jsonrpc_interface: String, flag_jsonrpc_port: u16, flag_jsonrpc_cors: String, flag_jsonrpc_apis: String, @@ -315,7 +316,7 @@ impl Configuration { fn author(&self) -> Address { let d = self.args.flag_etherbase.as_ref().unwrap_or(&self.args.flag_author); - Address::from_str(d).unwrap_or_else(|_| { + Address::from_str(clean_0x(d)).unwrap_or_else(|_| { die!("{}: Invalid address for --author. Must be 40 hex characters, without the 0x at the beginning.", d) }) } @@ -370,7 +371,7 @@ impl Configuration { fn init_nodes(&self, spec: &Spec) -> Vec { match self.args.flag_bootnodes { - Some(ref x) if x.len() > 0 => x.split(',').map(|s| { + Some(ref x) if !x.is_empty() => x.split(',').map(|s| { Self::normalize_enode(s).unwrap_or_else(|| { die!("{}: Invalid node address format given for a boot node.", s) }) @@ -409,6 +410,7 @@ impl Configuration { ret } + #[cfg_attr(feature="dev", allow(useless_format))] fn client_config(&self) -> ClientConfig { let mut client_config = ClientConfig::default(); match self.args.flag_cache { @@ -522,7 +524,11 @@ impl Configuration { // Setup rpc if self.args.flag_jsonrpc || self.args.flag_rpc { let url = format!("{}:{}", - self.args.flag_rpcaddr.as_ref().unwrap_or(&self.args.flag_jsonrpc_addr), + match self.args.flag_rpcaddr.as_ref().unwrap_or(&self.args.flag_jsonrpc_interface).as_str() { + "all" => "0.0.0.0", + "local" => "127.0.0.1", + x => x, + }, self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port) ); SocketAddr::from_str(&url).unwrap_or_else(|_| die!("{}: Invalid JSONRPC listen host/port given.", url)); diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 6e7efb31c..56eeb7d83 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -22,11 +22,11 @@ ethminer = { path = "../miner" } rustc-serialize = "0.3" transient-hashmap = "0.1" serde_macros = { version = "0.7.0", optional = true } -clippy = { version = "0.0.50", optional = true } +clippy = { version = "0.0.54", optional = true } [build-dependencies] serde_codegen = { version = "0.7.0", optional = true } -syntex = "0.29.0" +syntex = "0.30.0" [features] default = ["serde_codegen"] diff --git a/rpc/rpctest/Cargo.toml b/rpc/rpctest/Cargo.toml new file mode 100644 index 000000000..5b8f7f845 --- /dev/null +++ b/rpc/rpctest/Cargo.toml @@ -0,0 +1,17 @@ +[package] +description = "Rpc test client." +name = "rpctest" +version = "1.1.0" +license = "GPL-3.0" +authors = ["Ethcore "] + +[dependencies] +ctrlc = { git = "https://github.com/tomusdrw/rust-ctrlc.git" } +docopt = "0.6" +rustc-serialize = "0.3" +ethcore = { path = "../../ethcore" } +ethcore-devtools = { path = "../../devtools" } +ethcore-rpc = { path = ".." } +ethcore-util = { path = "../../util" } +ethjson = { path = "../../json" } +serde_json = "0.7.0" diff --git a/rpc/rpctest/src/main.rs b/rpc/rpctest/src/main.rs new file mode 100644 index 000000000..6cc747959 --- /dev/null +++ b/rpc/rpctest/src/main.rs @@ -0,0 +1,148 @@ +// 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 . + +extern crate ctrlc; +extern crate docopt; +extern crate rustc_serialize; +extern crate serde_json; +extern crate ethjson; +extern crate ethcore_util as util; +extern crate ethcore; +extern crate ethcore_devtools as devtools; +extern crate ethcore_rpc as rpc; + +use std::collections::HashMap; +use std::sync::{Arc, Mutex, Condvar}; +use std::process; +use std::fs::File; +use std::path::Path; +use docopt::Docopt; +use ctrlc::CtrlC; +use ethcore::spec::Genesis; +use ethcore::pod_state::PodState; +use ethcore::ethereum; +use ethcore::client::{BlockChainClient, Client, ClientConfig}; +use devtools::RandomTempPath; +use util::IoChannel; +use rpc::v1::tests::helpers::{TestSyncProvider, Config as SyncConfig, TestMinerService, TestAccountProvider, TestAccount}; +use rpc::v1::{Eth, EthClient, EthFilter, EthFilterClient}; +use util::panics::MayPanic; +use util::hash::Address; + +const USAGE: &'static str = r#" +Parity rpctest client. + By Wood/Paronyan/Kotewicz/Drwięga/Volf. + Copyright 2015, 2016 Ethcore (UK) Limited + +Usage: + rpctest --json --name [options] + rpctest --help + +Options: + --jsonrpc-addr HOST Specify the hostname portion of the JSONRPC API + server [default: 127.0.0.1]. + --jsonrpc-port PORT Specify the port portion of the JSONRPC API server + [default: 8545]. +"#; + +#[derive(Debug, RustcDecodable)] +struct Args { + arg_test_file: String, + arg_test_name: String, + flag_jsonrpc_addr: String, + flag_jsonrpc_port: u16, +} + +struct Configuration { + args: Args, +} + +impl Configuration { + fn parse() -> Self { + Configuration { + args: Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit()) + } + } + + fn execute(&self) { + println!("file path: {:?}", self.args.arg_test_file); + println!("test name: {:?}", self.args.arg_test_name); + + let path = Path::new(&self.args.arg_test_file); + let file = File::open(path).unwrap_or_else(|_| { + println!("Cannot open file."); + process::exit(1); + }); + + let tests: ethjson::blockchain::Test = serde_json::from_reader(file).unwrap_or_else(|err| { + println!("Invalid json file."); + println!("{:?}", err); + process::exit(2); + }); + + let blockchain = tests.get(&self.args.arg_test_name).unwrap_or_else(|| { + println!("Invalid test name."); + process::exit(3); + }); + + let genesis = Genesis::from(blockchain.genesis()); + let state = PodState::from(blockchain.pre_state.clone()); + let mut spec = ethereum::new_frontier_test(); + spec.set_genesis_state(state); + spec.overwrite_genesis_params(genesis); + assert!(spec.is_state_root_valid()); + + let temp = RandomTempPath::new(); + { + let client: Arc = Client::new(ClientConfig::default(), spec, temp.as_path(), IoChannel::disconnected()).unwrap(); + for b in &blockchain.blocks_rlp() { + let _ = client.import_block(b.clone()); + client.flush_queue(); + client.import_verified_blocks(&IoChannel::disconnected()); + } + let sync = Arc::new(TestSyncProvider::new(SyncConfig { + protocol_version: 65, + num_peers: 120 + })); + + let miner = Arc::new(TestMinerService::default()); + let mut accs = HashMap::new(); + accs.insert(Address::from(1), TestAccount::new("test")); + let accounts = Arc::new(TestAccountProvider::new(accs)); + let server = rpc::RpcServer::new(); + server.add_delegate(EthClient::new(&client, &sync, &accounts, &miner).to_delegate()); + server.add_delegate(EthFilterClient::new(&client, &miner).to_delegate()); + + let url = format!("{}:{}", self.args.flag_jsonrpc_addr, self.args.flag_jsonrpc_port); + let panic_handler = server.start_http(url.as_ref(), "*", 1); + let exit = Arc::new(Condvar::new()); + + let e = exit.clone(); + CtrlC::set_handler(move || { e.notify_all(); }); + + let e = exit.clone(); + panic_handler.on_panic(move |_reason| { e.notify_all(); }); + + let mutex = Mutex::new(()); + let _ = exit.wait(mutex.lock().unwrap()).unwrap(); + } + + } +} + +fn main() { + Configuration::parse().execute(); +} diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index fda391304..d7ee478bf 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -19,7 +19,7 @@ use std::collections::HashSet; use std::sync::{Arc, Weak, Mutex}; use std::ops::Deref; use ethsync::{SyncProvider, SyncState}; -use ethminer::{MinerService}; +use ethminer::{MinerService, AccountDetails}; use jsonrpc_core::*; use util::numbers::*; use util::sha3::*; @@ -31,7 +31,7 @@ use ethcore::ethereum::Ethash; use ethcore::ethereum::denominations::shannon; use ethcore::transaction::Transaction as EthTransaction; use v1::traits::{Eth, EthFilter}; -use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, OptionalValue, Index, Filter, Log}; +use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, OptionalValue, Index, Filter, Log, Receipt}; use v1::helpers::{PollFilter, PollManager, ExternalMinerService, ExternalMiner}; use util::keys::store::AccountProvider; @@ -103,7 +103,8 @@ impl EthClient timestamp: U256::from(view.timestamp()), difficulty: view.difficulty(), total_difficulty: total_difficulty, - uncles: vec![], + nonce: view.seal().get(1).map_or_else(H64::zero, |r| H64::from_slice(r)), + uncles: block_view.uncle_hashes(), transactions: { if include_txs { BlockTransactions::Full(block_view.localized_transactions().into_iter().map(From::from).collect()) @@ -111,7 +112,7 @@ impl EthClient BlockTransactions::Hashes(block_view.transaction_hashes()) } }, - extra_data: Bytes::default() + extra_data: Bytes::new(view.extra_data()) }; to_value(&block) }, @@ -229,32 +230,34 @@ impl Eth for EthClient fn block_transaction_count_by_hash(&self, params: Params) -> Result { from_params::<(H256,)>(params) .and_then(|(hash,)| // match - to_value(&take_weak!(self.client).block(BlockId::Hash(hash)) - .map_or_else(U256::zero, |bytes| U256::from(BlockView::new(&bytes).transactions_count())))) + take_weak!(self.client).block(BlockId::Hash(hash)) + .map_or(Ok(Value::Null), |bytes| to_value(&U256::from(BlockView::new(&bytes).transactions_count())))) } fn block_transaction_count_by_number(&self, params: Params) -> Result { from_params::<(BlockNumber,)>(params) .and_then(|(block_number,)| match block_number { - BlockNumber::Pending => to_value(&U256::from(take_weak!(self.miner).status().transaction_queue_pending)), - _ => to_value(&take_weak!(self.client).block(block_number.into()) - .map_or_else(U256::zero, |bytes| U256::from(BlockView::new(&bytes).transactions_count()))) + BlockNumber::Pending => to_value( + &U256::from(take_weak!(self.miner).status().transactions_in_pending_block) + ), + _ => take_weak!(self.client).block(block_number.into()) + .map_or(Ok(Value::Null), |bytes| to_value(&U256::from(BlockView::new(&bytes).transactions_count()))) }) } fn block_uncles_count_by_hash(&self, params: Params) -> Result { from_params::<(H256,)>(params) .and_then(|(hash,)| - to_value(&take_weak!(self.client).block(BlockId::Hash(hash)) - .map_or_else(U256::zero, |bytes| U256::from(BlockView::new(&bytes).uncles_count())))) + take_weak!(self.client).block(BlockId::Hash(hash)) + .map_or(Ok(Value::Null), |bytes| to_value(&U256::from(BlockView::new(&bytes).uncles_count())))) } fn block_uncles_count_by_number(&self, params: Params) -> Result { from_params::<(BlockNumber,)>(params) .and_then(|(block_number,)| match block_number { BlockNumber::Pending => to_value(&U256::from(0)), - _ => to_value(&take_weak!(self.client).block(block_number.into()) - .map_or_else(U256::zero, |bytes| U256::from(BlockView::new(&bytes).uncles_count()))) + _ => take_weak!(self.client).block(block_number.into()) + .map_or(Ok(Value::Null), |bytes| to_value(&U256::from(BlockView::new(&bytes).uncles_count()))) }) } @@ -290,6 +293,15 @@ impl Eth for EthClient .and_then(|(number, index)| self.transaction(TransactionId::Location(number.into(), index.value()))) } + fn transaction_receipt(&self, params: Params) -> Result { + from_params::<(H256,)>(params) + .and_then(|(hash,)| { + let client = take_weak!(self.client); + let receipt = client.transaction_receipt(TransactionId::Hash(hash)); + to_value(&receipt.map(Receipt::from)) + }) + } + fn uncle_by_block_hash_and_index(&self, params: Params) -> Result { from_params::<(H256, Index)>(params) .and_then(|(hash, index)| self.uncle(BlockId::Hash(hash), index.value())) @@ -321,6 +333,15 @@ impl Eth for EthClient fn work(&self, params: Params) -> Result { match params { Params::None => { + let client = take_weak!(self.client); + // check if we're still syncing and return empty strings int that case + { + let sync = take_weak!(self.sync); + if sync.status().state != SyncState::Idle && client.queue_info().is_empty() { + return to_value(&(String::new(), String::new(), String::new())); + } + } + let miner = take_weak!(self.miner); let client = take_weak!(self.client); let u = miner.sealing_block(client.deref()).lock().unwrap(); @@ -331,7 +352,7 @@ impl Eth for EthClient let seed_hash = Ethash::get_seedhash(b.block().header().number()); to_value(&(pow_hash, seed_hash, target)) } - _ => Err(Error::invalid_params()) + _ => Err(Error::internal_error()) } }, _ => Err(Error::invalid_params()) @@ -370,8 +391,11 @@ impl Eth for EthClient let signed_transaction = transaction.sign(&secret); let hash = signed_transaction.hash(); - let import = miner.import_transactions(vec![signed_transaction], |a: &Address| client.nonce(a)); - match import { + let import = miner.import_transactions(vec![signed_transaction], |a: &Address| AccountDetails { + nonce: client.nonce(a), + balance: client.balance(a), + }); + match import.into_iter().collect::, _>>() { Ok(_) => to_value(&hash), Err(e) => { warn!("Error sending transaction: {:?}", e); @@ -383,6 +407,50 @@ impl Eth for EthClient } }) } + + fn call(&self, params: Params) -> Result { + from_params::<(TransactionRequest, BlockNumber)>(params) + .and_then(|(transaction_request, _block_number)| { + let accounts = take_weak!(self.accounts); + match accounts.account_secret(&transaction_request.from) { + Ok(secret) => { + let client = take_weak!(self.client); + + let transaction: EthTransaction = transaction_request.into(); + let signed_transaction = transaction.sign(&secret); + + let output = client.call(&signed_transaction) + .map(|e| Bytes::new(e.output)) + .unwrap_or(Bytes::default()); + + to_value(&output) + }, + Err(_) => { to_value(&Bytes::default()) } + } + }) + } + + fn estimate_gas(&self, params: Params) -> Result { + from_params::<(TransactionRequest, BlockNumber)>(params) + .and_then(|(transaction_request, _block_number)| { + let accounts = take_weak!(self.accounts); + match accounts.account_secret(&transaction_request.from) { + Ok(secret) => { + let client = take_weak!(self.client); + + let transaction: EthTransaction = transaction_request.into(); + let signed_transaction = transaction.sign(&secret); + + let gas_used = client.call(&signed_transaction) + .map(|e| e.gas_used + e.refunded) + .unwrap_or(U256::zero()); + + to_value(&gas_used) + }, + Err(_) => { to_value(&U256::zero()) } + } + }) + } } /// Eth filter rpc implementation. diff --git a/rpc/src/v1/mod.rs b/rpc/src/v1/mod.rs index b82a20e89..c81f58156 100644 --- a/rpc/src/v1/mod.rs +++ b/rpc/src/v1/mod.rs @@ -23,8 +23,7 @@ mod impls; mod types; mod helpers; -#[cfg(test)] -mod tests; +pub mod tests; pub use self::traits::{Web3, Eth, EthFilter, Personal, Net}; pub use self::impls::*; diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 6bc929709..db18a853e 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -18,8 +18,8 @@ use std::collections::HashMap; use std::sync::{Arc, RwLock}; use jsonrpc_core::IoHandler; use util::hash::{Address, H256}; -use util::numbers::U256; -use ethcore::client::{TestBlockChainClient, EachBlockWith}; +use util::numbers::{Uint, U256}; +use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed}; use v1::{Eth, EthClient}; use v1::tests::helpers::{TestAccount, TestAccountProvider, TestSyncProvider, Config, TestMinerService, TestExternalMiner}; @@ -43,12 +43,12 @@ fn sync_provider() -> Arc { } fn miner_service() -> Arc { - Arc::new(TestMinerService) + Arc::new(TestMinerService::default()) } struct EthTester { - client: Arc, - _sync: Arc, + pub client: Arc, + pub sync: Arc, _accounts_provider: Arc, _miner: Arc, hashrates: Arc>>, @@ -68,7 +68,7 @@ impl Default for EthTester { io.add_delegate(eth); EthTester { client: client, - _sync: sync, + sync: sync, _accounts_provider: ap, _miner: miner, io: io, @@ -224,7 +224,7 @@ fn rpc_eth_block_transaction_count_by_hash() { "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"], "id": 1 }"#; - let response = r#"{"jsonrpc":"2.0","result":"0x00","id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":null,"id":1}"#; assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); } @@ -242,6 +242,20 @@ fn rpc_eth_transaction_count_by_number() { assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); } +#[test] +fn rpc_eth_transaction_count_by_number_pending() { + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getBlockTransactionCountByNumber", + "params": ["pending"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0x01","id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + + #[test] fn rpc_eth_uncle_count_by_block_hash() { let request = r#"{ @@ -250,7 +264,7 @@ fn rpc_eth_uncle_count_by_block_hash() { "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"], "id": 1 }"#; - let response = r#"{"jsonrpc":"2.0","result":"0x00","id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":null,"id":1}"#; assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); } @@ -285,9 +299,67 @@ fn rpc_eth_code() { } #[test] -#[ignore] fn rpc_eth_call() { - unimplemented!() + let tester = EthTester::default(); + tester.client.set_execution_result(Executed { + gas: U256::zero(), + gas_used: U256::from(0xff30), + refunded: U256::from(0x5), + cumulative_gas_used: U256::zero(), + logs: vec![], + contracts_created: vec![], + output: vec![0x12, 0x34, 0xff], + }); + + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_call", + "params": [{ + "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "value": "0x9184e72a", + "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" + }, + "latest"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0x1234ff","id":1}"#; + + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_estimate_gas() { + let tester = EthTester::default(); + tester.client.set_execution_result(Executed { + gas: U256::zero(), + gas_used: U256::from(0xff30), + refunded: U256::from(0x5), + cumulative_gas_used: U256::zero(), + logs: vec![], + contracts_created: vec![], + output: vec![0x12, 0x34, 0xff], + }); + + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_estimateGas", + "params": [{ + "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "value": "0x9184e72a", + "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" + }, + "latest"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0xff35","id":1}"#; + + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); } #[test] @@ -308,12 +380,6 @@ fn rpc_eth_sign() { unimplemented!() } -#[test] -#[ignore] -fn rpc_eth_estimate_gas() { - unimplemented!() -} - #[test] fn rpc_eth_compilers() { let request = r#"{"jsonrpc": "2.0", "method": "eth_getCompilers", "params": [], "id": 1}"#; @@ -346,5 +412,25 @@ fn rpc_eth_compile_serpent() { assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); } +#[test] +fn returns_no_work_if_cant_mine() { + let eth_tester = EthTester::default(); + let request = r#"{"jsonrpc": "2.0", "method": "eth_getWork", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":["","",""],"id":1}"#; + assert_eq!(eth_tester.io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn returns_error_if_can_mine_and_no_closed_block() { + use ethsync::{SyncState}; + + let eth_tester = EthTester::default(); + eth_tester.sync.status.write().unwrap().state = SyncState::Idle; + + let request = r#"{"jsonrpc": "2.0", "method": "eth_getWork", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","error":{"code":-32603,"message":"Internal error","data":null},"id":1}"#; + + assert_eq!(eth_tester.io.handle_request(request), Some(response.to_owned())); +} diff --git a/rpc/src/v1/tests/helpers/account_provider.rs b/rpc/src/v1/tests/helpers/account_provider.rs index ce5b76b44..6ef6e2b59 100644 --- a/rpc/src/v1/tests/helpers/account_provider.rs +++ b/rpc/src/v1/tests/helpers/account_provider.rs @@ -14,10 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Test implementation of account provider. + use std::sync::RwLock; use std::collections::HashMap; use std::io; -use util::hash::{Address, H256}; +use util::hash::{Address, H256, FixedHash}; use util::crypto::{Secret, Signature}; use util::keys::store::{AccountProvider, SigningError, EncryptedHashMapError}; @@ -31,6 +33,7 @@ pub struct TestAccount { } impl TestAccount { + /// Creates new test account. pub fn new(password: &str) -> Self { TestAccount { unlocked: false, @@ -42,6 +45,7 @@ impl TestAccount { /// Test account provider. pub struct TestAccountProvider { accounts: RwLock>, + /// Added accounts passwords. pub adds: RwLock>, } @@ -79,7 +83,7 @@ impl AccountProvider for TestAccountProvider { } fn account_secret(&self, _account: &Address) -> Result { - unimplemented!() + Ok(Secret::random()) } fn sign(&self, _account: &Address, _message: &H256) -> Result { diff --git a/rpc/src/v1/tests/helpers/external_miner.rs b/rpc/src/v1/tests/helpers/external_miner.rs index a5111b302..1799c36c5 100644 --- a/rpc/src/v1/tests/helpers/external_miner.rs +++ b/rpc/src/v1/tests/helpers/external_miner.rs @@ -22,10 +22,12 @@ use v1::helpers::ExternalMinerService; /// Test ExternalMinerService; pub struct TestExternalMiner { + /// External miners hashrates. pub hashrates: Arc>> } impl TestExternalMiner { + /// Creates new external miner. pub fn new(hashrates: Arc>>) -> Self { TestExternalMiner { hashrates: hashrates, diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index 0cddf2a1e..7f07341bf 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -14,26 +14,50 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use util::{Address, H256, U256, Bytes}; +//! Test implementation of miner service. + +use util::{Address, H256, Bytes}; use util::standard::*; use ethcore::error::Error; use ethcore::client::BlockChainClient; use ethcore::block::ClosedBlock; use ethcore::transaction::SignedTransaction; -use ethminer::{MinerService, MinerStatus}; +use ethminer::{MinerService, MinerStatus, AccountDetails}; -pub struct TestMinerService; +/// Test miner service. +pub struct TestMinerService { + /// Imported transactions. + pub imported_transactions: RwLock>, + /// Latest closed block. + pub latest_closed_block: Mutex>, +} + +impl Default for TestMinerService { + fn default() -> TestMinerService { + TestMinerService { + imported_transactions: RwLock::new(Vec::new()), + latest_closed_block: Mutex::new(None), + } + } +} impl MinerService for TestMinerService { /// Returns miner's status. - fn status(&self) -> MinerStatus { unimplemented!(); } + fn status(&self) -> MinerStatus { + MinerStatus { + transactions_in_pending_queue: 0, + transactions_in_future_queue: 0, + transactions_in_pending_block: 1 + } + } /// Imports transactions to transaction queue. - fn import_transactions(&self, _transactions: Vec, _fetch_nonce: T) -> Result<(), Error> where T: Fn(&Address) -> U256 { unimplemented!(); } + fn import_transactions(&self, _transactions: Vec, _fetch_account: T) -> Vec> + where T: Fn(&Address) -> AccountDetails { unimplemented!(); } /// Returns hashes of transactions currently in pending - fn pending_transactions_hashes(&self) -> Vec { unimplemented!(); } + fn pending_transactions_hashes(&self) -> Vec { vec![] } /// Removes all transactions from the queue and restart mining operation. fn clear_and_reset(&self, _chain: &BlockChainClient) { unimplemented!(); } @@ -42,12 +66,14 @@ impl MinerService for TestMinerService { fn chain_new_blocks(&self, _chain: &BlockChainClient, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) { unimplemented!(); } /// New chain head event. Restart mining operation. - fn prepare_sealing(&self, _chain: &BlockChainClient) { unimplemented!(); } + fn update_sealing(&self, _chain: &BlockChainClient) { unimplemented!(); } /// Grab the `ClosedBlock` that we want to be sealed. Comes as a mutex that you have to lock. - fn sealing_block(&self, _chain: &BlockChainClient) -> &Mutex> { unimplemented!(); } + fn sealing_block(&self, _chain: &BlockChainClient) -> &Mutex> { + &self.latest_closed_block + } /// Submit `seal` as a valid solution for the header of `pow_hash`. /// Will check the seal, but not actually insert the block into the chain. fn submit_seal(&self, _chain: &BlockChainClient, _pow_hash: H256, _seal: Vec) -> Result<(), Error> { unimplemented!(); } -} \ No newline at end of file +} diff --git a/rpc/src/v1/tests/helpers/mod.rs b/rpc/src/v1/tests/helpers/mod.rs index fc652e7d6..c9db61f6d 100644 --- a/rpc/src/v1/tests/helpers/mod.rs +++ b/rpc/src/v1/tests/helpers/mod.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Test rpc services. + mod account_provider; mod sync_provider; mod miner_service; diff --git a/rpc/src/v1/tests/helpers/sync_provider.rs b/rpc/src/v1/tests/helpers/sync_provider.rs index 631752dfc..48b4f55a9 100644 --- a/rpc/src/v1/tests/helpers/sync_provider.rs +++ b/rpc/src/v1/tests/helpers/sync_provider.rs @@ -14,21 +14,30 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethsync::{SyncProvider, SyncStatus, SyncState}; +//! Test implementation of SyncProvider. +use ethsync::{SyncProvider, SyncStatus, SyncState}; +use std::sync::{RwLock}; + +/// TestSyncProvider config. pub struct Config { + /// Protocol version. pub protocol_version: u8, + /// Number of peers. pub num_peers: usize, } +/// Test sync provider. pub struct TestSyncProvider { - status: SyncStatus, + /// Sync status. + pub status: RwLock, } impl TestSyncProvider { + /// Creates new sync provider. pub fn new(config: Config) -> Self { TestSyncProvider { - status: SyncStatus { + status: RwLock::new(SyncStatus { state: SyncState::NotSynced, protocol_version: config.protocol_version, start_block_number: 0, @@ -39,14 +48,14 @@ impl TestSyncProvider { num_peers: config.num_peers, num_active_peers: 0, mem_used: 0, - }, + }), } } } impl SyncProvider for TestSyncProvider { fn status(&self) -> SyncStatus { - self.status.clone() + self.status.read().unwrap().clone() } } diff --git a/rpc/src/v1/tests/mod.rs b/rpc/src/v1/tests/mod.rs index 21085a0fd..7a6340ce1 100644 --- a/rpc/src/v1/tests/mod.rs +++ b/rpc/src/v1/tests/mod.rs @@ -16,8 +16,12 @@ //!TODO: load custom blockchain state and test +pub mod helpers; +#[cfg(test)] mod eth; +#[cfg(test)] mod net; +#[cfg(test)] mod web3; -mod helpers; +#[cfg(test)] mod personal; diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index 2457efcf8..ac334dd2b 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -63,7 +63,8 @@ pub struct Block { pub difficulty: U256, #[serde(rename="totalDifficulty")] pub total_difficulty: U256, - pub uncles: Vec, + pub nonce: H64, + pub uncles: Vec, pub transactions: BlockTransactions } @@ -78,7 +79,7 @@ mod tests { fn test_serialize_block_transactions() { let t = BlockTransactions::Full(vec![Transaction::default()]); let serialized = serde_json::to_string(&t).unwrap(); - assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x00"}]"#); + assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x"}]"#); let t = BlockTransactions::Hashes(vec![H256::default()]); let serialized = serde_json::to_string(&t).unwrap(); @@ -104,11 +105,12 @@ mod tests { timestamp: U256::default(), difficulty: U256::default(), total_difficulty: U256::default(), + nonce: H64::default(), uncles: vec![], transactions: BlockTransactions::Hashes(vec![]) }; let serialized = serde_json::to_string(&block).unwrap(); - assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","author":"0x0000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","number":"0x00","gasUsed":"0x00","gasLimit":"0x00","extraData":"0x00","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x00","difficulty":"0x00","totalDifficulty":"0x00","uncles":[],"transactions":[]}"#); + assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","author":"0x0000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","number":"0x00","gasUsed":"0x00","gasLimit":"0x00","extraData":"0x","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x00","difficulty":"0x00","totalDifficulty":"0x00","nonce":"0x0000000000000000","uncles":[],"transactions":[]}"#); } } diff --git a/rpc/src/v1/types/bytes.rs b/rpc/src/v1/types/bytes.rs index 0b14c30e8..8c47806f8 100644 --- a/rpc/src/v1/types/bytes.rs +++ b/rpc/src/v1/types/bytes.rs @@ -20,7 +20,7 @@ use serde::de::Visitor; use util::common::FromHex; /// Wrapper structure around vector of bytes. -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Default)] pub struct Bytes(Vec); impl Bytes { @@ -31,13 +31,6 @@ impl Bytes { pub fn to_vec(self) -> Vec { let Bytes(x) = self; x } } -impl Default for Bytes { - fn default() -> Self { - // default serialized value is 0x00 - Bytes(vec![0]) - } -} - impl Serialize for Bytes { fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { diff --git a/rpc/src/v1/types/mod.rs.in b/rpc/src/v1/types/mod.rs.in index ebc3bc0ff..0121e4aea 100644 --- a/rpc/src/v1/types/mod.rs.in +++ b/rpc/src/v1/types/mod.rs.in @@ -24,6 +24,7 @@ mod optionals; mod sync; mod transaction; mod transaction_request; +mod receipt; pub use self::block::{Block, BlockTransactions}; pub use self::block_number::BlockNumber; @@ -35,4 +36,5 @@ pub use self::optionals::OptionalValue; pub use self::sync::{SyncStatus, SyncInfo}; pub use self::transaction::Transaction; pub use self::transaction_request::TransactionRequest; +pub use self::receipt::Receipt; diff --git a/rpc/src/v1/types/receipt.rs b/rpc/src/v1/types/receipt.rs new file mode 100644 index 000000000..fa34d5df5 --- /dev/null +++ b/rpc/src/v1/types/receipt.rs @@ -0,0 +1,56 @@ +// 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 . + +use util::numbers::U256; +use util::hash::{Address, H256}; +use v1::types::Log; +use ethcore::receipt::LocalizedReceipt; + +#[derive(Debug, Serialize)] +pub struct Receipt { + #[serde(rename="transactionHash")] + pub transaction_hash: H256, + #[serde(rename="transactionIndex")] + pub transaction_index: U256, + #[serde(rename="blockHash")] + pub block_hash: H256, + #[serde(rename="blockNumber")] + pub block_number: U256, + #[serde(rename="cumulativeGasUsed")] + pub cumulative_gas_used: U256, + #[serde(rename="gasUsed")] + pub gas_used: U256, + #[serde(rename="contractAddress")] + pub contract_address: Option
, + pub logs: Vec, +} + +impl From for Receipt { + fn from(r: LocalizedReceipt) -> Self { + Receipt { + transaction_hash: r.transaction_hash, + transaction_index: U256::from(r.transaction_index), + block_hash: r.block_hash, + block_number: U256::from(r.block_number), + cumulative_gas_used: r.cumulative_gas_used, + gas_used: r.gas_used, + contract_address: r.contract_address, + logs: r.logs.into_iter().map(From::from).collect(), + } + } +} + + diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index 232cf0bf3..d809d19b4 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -67,7 +67,7 @@ mod tests { fn test_transaction_serialize() { let t = Transaction::default(); let serialized = serde_json::to_string(&t).unwrap(); - assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x00"}"#); + assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x"}"#); } } diff --git a/rpc/src/v1/types/transaction_request.rs b/rpc/src/v1/types/transaction_request.rs index d40402ab5..ed4dc19a2 100644 --- a/rpc/src/v1/types/transaction_request.rs +++ b/rpc/src/v1/types/transaction_request.rs @@ -46,6 +46,8 @@ impl Into for TransactionRequest { #[cfg(test)] mod tests { + use std::str::FromStr; + use rustc_serialize::hex::FromHex; use serde_json; use util::numbers::{Uint, U256}; use util::hash::Address; @@ -121,6 +123,29 @@ mod tests { }); } + #[test] + fn transaction_request_deserialize2() { + let s = r#"{ + "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "value": "0x9184e72a", + "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" + }"#; + let deserialized: TransactionRequest = serde_json::from_str(s).unwrap(); + + assert_eq!(deserialized, TransactionRequest { + from: Address::from_str("b60e8dd61c5d32be8058bb8eb970870f07233155").unwrap(), + to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()), + gas_price: Some(U256::from_str("9184e72a000").unwrap()), + gas: Some(U256::from_str("76c0").unwrap()), + value: Some(U256::from_str("9184e72a").unwrap()), + data: Some(Bytes::new("d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675".from_hex().unwrap())), + nonce: None + }); + } + #[test] fn transaction_request_deserialize_empty() { let s = r#"{"from":"0x0000000000000000000000000000000000000001"}"#; diff --git a/sync/Cargo.toml b/sync/Cargo.toml index ae268e010..635916bf3 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Ethcore Result<(), PacketDecodeError> { + // accepting transactions once only fully synced + if !io.is_chain_queue_empty() { + return Ok(()); + } + let item_count = r.item_count(); trace!(target: "sync", "{} -> Transactions ({} entries)", peer_id, item_count); @@ -940,8 +951,11 @@ impl ChainSync { transactions.push(tx); } let chain = io.chain(); - let fetch_nonce = |a: &Address| chain.nonce(a); - let _ = self.miner.import_transactions(transactions, fetch_nonce); + let fetch_account = |a: &Address| AccountDetails { + nonce: chain.nonce(a), + balance: chain.balance(a), + }; + let _ = self.miner.import_transactions(transactions, fetch_account); Ok(()) } @@ -1273,15 +1287,17 @@ impl ChainSync { /// called when block is imported to chain, updates transactions queue and propagates the blocks pub fn chain_new_blocks(&mut self, io: &mut SyncIo, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]) { - // Notify miner - self.miner.chain_new_blocks(io.chain(), imported, invalid, enacted, retracted); - // Propagate latests blocks - self.propagate_latest_blocks(io); + if io.is_chain_queue_empty() { + // Notify miner + self.miner.chain_new_blocks(io.chain(), imported, invalid, enacted, retracted); + // Propagate latests blocks + self.propagate_latest_blocks(io); + } // TODO [todr] propagate transactions? } pub fn chain_new_head(&mut self, io: &mut SyncIo) { - self.miner.prepare_sealing(io.chain()); + self.miner.update_sealing(io.chain()); } } @@ -1292,6 +1308,7 @@ mod tests { use ::SyncConfig; use util::*; use super::{PeerInfo, PeerAsking}; + use ethcore::views::BlockView; use ethcore::header::*; use ethcore::client::*; use ethminer::{Miner, MinerService}; @@ -1622,19 +1639,53 @@ mod tests { let good_blocks = vec![client.block_hash_delta_minus(2)]; let retracted_blocks = vec![client.block_hash_delta_minus(1)]; + // Add some balance to clients + for h in vec![good_blocks[0], retracted_blocks[0]] { + let block = client.block(BlockId::Hash(h)).unwrap(); + let view = BlockView::new(&block); + client.set_balance(view.transactions()[0].sender().unwrap(), U256::from(1_000_000_000)); + } + let mut queue = VecDeque::new(); let mut io = TestIo::new(&mut client, &mut queue, None); // when sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks); - assert_eq!(sync.miner.status().transaction_queue_future, 0); - assert_eq!(sync.miner.status().transaction_queue_pending, 1); + assert_eq!(sync.miner.status().transactions_in_future_queue, 0); + assert_eq!(sync.miner.status().transactions_in_pending_queue, 1); sync.chain_new_blocks(&mut io, &good_blocks, &[], &[], &retracted_blocks); // then let status = sync.miner.status(); - assert_eq!(status.transaction_queue_pending, 1); - assert_eq!(status.transaction_queue_future, 0); + assert_eq!(status.transactions_in_pending_queue, 1); + assert_eq!(status.transactions_in_future_queue, 0); + } + + #[test] + fn should_not_add_transactions_to_queue_if_not_synced() { + // given + let mut client = TestBlockChainClient::new(); + client.add_blocks(98, EachBlockWith::Uncle); + client.add_blocks(1, EachBlockWith::UncleAndTransaction); + client.add_blocks(1, EachBlockWith::Transaction); + let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); + + let good_blocks = vec![client.block_hash_delta_minus(2)]; + let retracted_blocks = vec![client.block_hash_delta_minus(1)]; + + let mut queue = VecDeque::new(); + let mut io = TestIo::new(&mut client, &mut queue, None); + + // when + sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks); + assert_eq!(sync.miner.status().transactions_in_future_queue, 0); + assert_eq!(sync.miner.status().transactions_in_pending_queue, 0); + sync.chain_new_blocks(&mut io, &good_blocks, &[], &[], &retracted_blocks); + + // then + let status = sync.miner.status(); + assert_eq!(status.transactions_in_pending_queue, 0); + assert_eq!(status.transactions_in_future_queue, 0); } #[test] diff --git a/sync/src/io.rs b/sync/src/io.rs index 00ee49be4..84697a021 100644 --- a/sync/src/io.rs +++ b/sync/src/io.rs @@ -37,6 +37,10 @@ pub trait SyncIo { fn peer_info(&self, peer_id: PeerId) -> String { peer_id.to_string() } + /// Returns if the chain block queue empty + fn is_chain_queue_empty(&self) -> bool { + self.chain().queue_info().is_empty() + } } /// Wraps `NetworkContext` and the blockchain client diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 1c87da2de..a4f6eff38 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -173,7 +173,7 @@ impl NetworkProtocolHandler for EthSync { SyncMessage::NewChainHead => { let mut sync_io = NetSyncIo::new(io, self.chain.deref()); self.sync.write().unwrap().chain_new_head(&mut sync_io); - } + }, _ => {/* Ignore other messages */}, } } diff --git a/util/Cargo.toml b/util/Cargo.toml index c0d106c1e..dd712317c 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -27,7 +27,7 @@ crossbeam = "0.2" slab = "0.1" sha3 = { path = "sha3" } serde = "0.7.0" -clippy = { version = "0.0.50", optional = true } +clippy = { version = "0.0.54", optional = true } json-tests = { path = "json-tests" } igd = "0.4.2" ethcore-devtools = { path = "../devtools" } diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index d185750c2..7bc6007ed 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -490,6 +490,8 @@ pub trait Uint: Sized + Default + FromStr + From + fmt::Debug + fmt::Displa fn zero() -> Self; /// Returns new instance equalling one. fn one() -> Self; + /// Returns the largest value that can be represented by this integer type. + fn max_value() -> Self; /// Error type for converting from a decimal string. type FromDecStrErr; @@ -647,6 +649,15 @@ macro_rules! construct_uint { From::from(1u64) } + #[inline] + fn max_value() -> Self { + let mut result = [0; $n_words]; + for i in 0..$n_words { + result[i] = u64::max_value(); + } + $name(result) + } + /// Fast exponentation by squaring /// https://en.wikipedia.org/wiki/Exponentiation_by_squaring fn pow(self, expon: Self) -> Self { diff --git a/util/build.rs b/util/build.rs index 1ec89f704..f033e52e0 100644 --- a/util/build.rs +++ b/util/build.rs @@ -26,12 +26,12 @@ use std::path::Path; fn main() { vergen(OutputFns::all()).unwrap(); let out_dir = env::var("OUT_DIR").unwrap(); - let dest_path = Path::new(&out_dir).join("rustc_version.rs"); - let mut f = File::create(&dest_path).unwrap(); + let dest_path = Path::new(&out_dir).join("rustc_version.rs"); + let mut f = File::create(&dest_path).unwrap(); f.write_all(format!(" /// Returns compiler version. - pub fn rustc_version() -> &'static str {{ + pub fn rustc_version() -> &'static str {{ \"{}\" - }} - ", rustc_version::version()).as_bytes()).unwrap(); + }} + ", rustc_version::version()).as_bytes()).unwrap(); } diff --git a/util/src/hash.rs b/util/src/hash.rs index fce0720d1..b7fddbe8b 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -63,7 +63,8 @@ pub trait FixedHash: Sized + BytesConvertable + Populatable + FromStr + Default fn low_u64(&self) -> u64; } -fn clean_0x(s: &str) -> &str { +/// Return `s` without the `0x` at the beginning of it, if any. +pub fn clean_0x(s: &str) -> &str { if s.len() >= 2 && &s[0..2] == "0x" { &s[2..] } else { diff --git a/util/src/journaldb/archivedb.rs b/util/src/journaldb/archivedb.rs index 83a80b7c2..76f0ecc50 100644 --- a/util/src/journaldb/archivedb.rs +++ b/util/src/journaldb/archivedb.rs @@ -175,6 +175,8 @@ impl JournalDB for ArchiveDB { #[cfg(test)] mod tests { + #![cfg_attr(feature="dev", allow(blacklisted_name))] + use common::*; use super::*; use hashdb::*; @@ -371,7 +373,7 @@ mod tests { jdb.commit(5, &b"5".sha3(), Some((4, b"4".sha3()))).unwrap(); } } - + #[test] fn reopen_fork() { let mut dir = ::std::env::temp_dir(); diff --git a/util/src/journaldb/earlymergedb.rs b/util/src/journaldb/earlymergedb.rs index 7cb00b993..15dcacd6a 100644 --- a/util/src/journaldb/earlymergedb.rs +++ b/util/src/journaldb/earlymergedb.rs @@ -527,6 +527,8 @@ impl JournalDB for EarlyMergeDB { #[cfg(test)] mod tests { + #![cfg_attr(feature="dev", allow(blacklisted_name))] + use common::*; use super::*; use super::super::traits::JournalDB; diff --git a/util/src/journaldb/overlayrecentdb.rs b/util/src/journaldb/overlayrecentdb.rs index efbd26c3b..102e23407 100644 --- a/util/src/journaldb/overlayrecentdb.rs +++ b/util/src/journaldb/overlayrecentdb.rs @@ -358,6 +358,8 @@ impl HashDB for OverlayRecentDB { #[cfg(test)] mod tests { + #![cfg_attr(feature="dev", allow(blacklisted_name))] + use common::*; use super::*; use hashdb::*; diff --git a/util/src/journaldb/refcounteddb.rs b/util/src/journaldb/refcounteddb.rs index 590964247..a8c3ff12b 100644 --- a/util/src/journaldb/refcounteddb.rs +++ b/util/src/journaldb/refcounteddb.rs @@ -28,7 +28,7 @@ use std::env; /// Implementation of the HashDB trait for a disk-backed database with a memory overlay /// and latent-removal semantics. /// -/// Like OverlayDB, there is a memory overlay; `commit()` must be called in order to +/// Like OverlayDB, there is a memory overlay; `commit()` must be called in order to /// write operations out to disk. Unlike OverlayDB, `remove()` operations do not take effect /// immediately. Rather some age (based on a linear but arbitrary metric) must pass before /// the removals actually take effect. @@ -113,7 +113,7 @@ impl JournalDB for RefCountedDB { } fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { - // journal format: + // journal format: // [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] // [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] // [era, n] => [ ... ] @@ -121,7 +121,7 @@ impl JournalDB for RefCountedDB { // TODO: store last_era, reclaim_period. // when we make a new commit, we journal the inserts and removes. - // for each end_era that we journaled that we are no passing by, + // for each end_era that we journaled that we are no passing by, // we remove all of its removes assuming it is canonical and all // of its inserts otherwise. @@ -147,7 +147,7 @@ impl JournalDB for RefCountedDB { r.append(&self.inserts); r.append(&self.removes); try!(batch.put(&last, r.as_raw())); - + trace!(target: "rcdb", "new journal for time #{}.{} => {}: inserts={:?}, removes={:?}", now, index, id, self.inserts, self.removes); self.inserts.clear(); @@ -194,6 +194,8 @@ impl JournalDB for RefCountedDB { #[cfg(test)] mod tests { + #![cfg_attr(feature="dev", allow(blacklisted_name))] + use common::*; use super::*; use super::super::traits::JournalDB; diff --git a/util/src/misc.rs b/util/src/misc.rs index 14fcf522a..190cb4130 100644 --- a/util/src/misc.rs +++ b/util/src/misc.rs @@ -88,7 +88,7 @@ pub fn version_data() -> Bytes { u32::from_str(env!("CARGO_PKG_VERSION_PATCH")).unwrap(); s.append(&v); s.append(&"Parity"); - s.append(&format!("{}", rustc_version())); + s.append(&rustc_version()); s.append(&&Target::os()[0..2]); s.out() } diff --git a/util/src/network/ip_utils.rs b/util/src/network/ip_utils.rs index 9696c601d..b37a47064 100644 --- a/util/src/network/ip_utils.rs +++ b/util/src/network/ip_utils.rs @@ -42,7 +42,7 @@ impl SocketAddrExt for Ipv4Addr { fn is_global_s(&self) -> bool { !self.is_private() && !self.is_loopback() && !self.is_link_local() && - !self.is_broadcast() && !self.is_documentation() + !self.is_broadcast() && !self.is_documentation() } } @@ -216,6 +216,8 @@ fn can_map_external_address_or_fail() { #[test] fn ipv4_properties() { + + #![cfg_attr(feature="dev", allow(too_many_arguments))] fn check(octets: &[u8; 4], unspec: bool, loopback: bool, private: bool, link_local: bool, global: bool, multicast: bool, broadcast: bool, documentation: bool) { @@ -262,7 +264,7 @@ fn ipv6_properties() { assert_eq!(ip.is_global_s(), global); } - // unspec loopbk global + // unspec loopbk global check("::", true, false, true); check("::1", false, true, false); }