diff --git a/.gitignore b/.gitignore index 90750f379..3226ea5a2 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,7 @@ # jetbrains ide stuff .idea +*.iml + +# Build artifacts +out/ diff --git a/.travis.yml b/.travis.yml index b2859589b..f66b38c51 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,56 +8,79 @@ branches: - /^stable-.*$/ - /^beta$/ - /^stable$/ +git: + depth: 3 matrix: fast_finish: true - include: + allow_failures: - rust: nightly - env: FEATURES="--features ethcore/json-tests" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" + include: + - rust: stable + 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" + - RUST_BACKTRACE="1" cache: apt: true directories: - - target/debug/deps - - target/debug/build - - target/release/deps - - target/release/build + - $TRAVIS_BUILD_DIR/target + - $HOME/.cargo addons: apt: packages: - libcurl4-openssl-dev - libelf-dev - libdw-dev -before_script: | - sudo add-apt-repository "deb http://ppa.launchpad.net/giskou/librocksdb/ubuntu trusty main" && - sudo apt-get update && - sudo apt-get install -y --force-yes librocksdb + 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 /.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 /.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 /.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 /.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 /.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 --coveralls-id=${TRAVIS_JOB_ID} --exclude-pattern /.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 = nightly ] && + [ $TRAVIS_RUST_VERSION = stable ] && cargo doc --no-deps --verbose ${KCOV_FEATURES} ${TARGETS} && echo '' > target/doc/index.html && 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: - - secure: 3sUjNi9mhdL5h1GTm8LONnDN/SYvUHT+WSkMl93h3nYiLCQXk8eZaPS98AS7oOaTsfW4UvnwckVFCFl49ttInsv4cd/TkAxmrJHe6kPyS9/4NWUdmP8BjicbBvL/ioSdXMECMEYzPDLV+I3KhtC2LcB6ceDEl/XwMOJlzbGf7RbtcXGVQgMLqSYY1YKjQA4vbT5nFgIS/sZu3Z9yFgN0GafnihKcizqoHhdJjs/zxmX+qJepnC6o3V6KcFnS7QHhM1JOr85twE6S422UlvNaEb5ovwLPqmOl5+fA+6shbx4AxFTY6E9Iors+OVY/JliFhrqOdCt0i2P1FUHN4kbGZQkf0rphN/ZOI2uKNFTOyXiPvppfo/ZemKmcqkwkqP9+lf5QqYmtE6hsAYagxn49xJZILl8tAYbdqxF5gxa+TEVrfsBFtz/Sv3q8QhKQNPAmjEcKyMatyEreLUIFEpFTGIco8jN4eXeSoLRdJ+Z75ihttfQWhNfUDgNL30iQLy0AgFSsh/cyb5M8y9lxrGDzDTogvaiKGwr/V45sPkcXWCkmOgMdINqBB6ZtdL3bGHdyjmYj+y3btjf3aP11k++BL0fXIaKn25aS/p/9iyGb1FyGCM03o4ZRQ3YhTOvfMRfRGf6nWbaMx9upv8o5ShSdysewhrnh3082r7u896ny1Ho= - - secure: 0/FeVvFl3AhBW0TCPoujY9zOAYoUNMlAz3XjC04vlc4Ksfx0lGU3KFi97LlALxMWV0lfwQc7ixSe2vTgQVQuLVSU9XEW40fQgEjJlmLca2RcRx1kfzJDypuWSiCME7MWmLPH0ac4COdTDS1z5WGggv5YB7GQPCzFvcmOOaPYtF29ngCtkyB2HmNkY/W3omHFEk7Si6bsmOSHZiOAhivPl6ixnGpFyTEKPyraMMqPIj5rbEGkzgeLTiXf2ur143n/tnSr8tmP1MfQi9yS8/ONidMqnxUeuLkeNnb82zj9pVJhVXq0xF44WXJ8Za1jm0ByiTakgqpm8Juk822qjvtNulJ1XZW/fyZQZaN1dy3uq5Ud3W8wS9M7VIVl8CoXozzDpIsdPeUAtkAxeHBsZqL1vAH2yC1YJA7HPySMYzCjYqkJ2r62xYk0gXmNXphfU+F/X/rHzHsTMJPONJ54HQwu12m7zVlKIYBGHgEXg/HAM/g4ljUzl6WWR/nHH/tQM8ND/8FpHluJSZJWacq/1QNhVdTq2x6cqws2fs5A7nVpccR9+6RRgYgv6+YS2LxvFzByuZveGGoKif+uMECXN876j40araUqU528Yz9i8bHJlnM3coRBndaLNWByLcUyXCB9r9IUosUu41rr+L2mVzkSDm0GicuNCzqvzYQ9Q6QY4uQ= - - secure: DglvLR27MrBKQO/8s7ZfGqfimXk1Iq5MreCTc+ZkWMkZ0sDP76YBUPq5j25hcg0Z09z09O2Q5OUOyYkhVD4AnRjoRLUplHdpDE9CBSz2vUGpMpzhgAqzBc6SDsEmWU2JlAPBraIODXQdP/Qo6tYY4zn3vwd/VFKo27GTb5b60WAkTVvT/0YPWycEXFIa7sNMgjNI0EnT+Se5USDYwb6MM1T9JxJot0q3WtOnsVyroCHJp4QDicpS8eQIu3Tl+SLE4d0EoJ4YYLOI+jWOybipuO1xM1xlHq/gpWfjKqbJh24xtAds524dN7ujfjAhyO2zQbuTOfi7QVOj/Go0tGYxNxobR4pYG783Aiq3Quj0GzSrLEAatkk5tGOcuVJ98EYIg3WPJuC93waTTXcS0xDyy09XHxWxZ/5PiXorRZjpHvnZfRF0X4Mus6jUJ7hqDuOUiF5BI1RHomHvJQQHUrLdmh7OHyrer3YUpKRs65tww6H+VM+lKNa3MnMkB5+or/co14svs7I4pni9S+aZg//bwuxGVXchK6bjLCP1X99Ar4fA5EGsTVdjp3PRqutM/P3RqNGkwTczat/PNZ8fFAD9y7pDs2L6YkqpflTC9d6vKTSl6gORGw6ltLUJs23ON6xRNIBMw1cXp67wN57vF46TPt1i3ZlIQsYn0pAVNKavbZE= deploy: provider: releases diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index f679363b8..000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,12 +0,0 @@ -# Contributing to Parity - -## License - -By contributing to Parity, you agree that your contributions will be -licensed under the [BSD License](LICENSE). - -At the top of every source code file you alter, after the initial -licence section, please append a second section that reads: - -Portions contributed by YOUR NAME are hereby placed under the BSD licence. - diff --git a/Cargo.lock b/Cargo.lock index 1fa63e621..14ebabb6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,25 +1,31 @@ [root] name = "parity" -version = "0.9.0" +version = "1.1.0" dependencies = [ - "clippy 0.0.41 (registry+https://github.com/rust-lang/crates.io-index)", - "ctrlc 1.0.1 (git+https://github.com/tomusdrw/rust-ctrlc.git)", + "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)", - "docopt_macros 0.6.81 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 0.9.0", - "ethcore-rpc 0.9.0", - "ethcore-util 0.9.0", - "ethsync 0.1.0", + "ethcore 1.1.0", + "ethcore-devtools 1.1.0", + "ethcore-rpc 1.1.0", + "ethcore-util 1.1.0", + "ethminer 1.1.0", + "ethsync 1.1.0", "fdlimit 0.1.0", "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)", + "number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rpassword 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "aho-corasick" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -27,7 +33,7 @@ dependencies = [ [[package]] name = "arrayvec" -version = "0.3.15" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "nodrop 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -36,8 +42,23 @@ dependencies = [ [[package]] name = "aster" -version = "0.12.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "syntex_syntax 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bigint" +version = "0.1.0" +dependencies = [ + "arrayvec 0.3.16 (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)", + "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "bitflags" @@ -46,7 +67,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "0.4.0" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "blastfig" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -60,12 +86,22 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "clippy" -version = "0.0.41" +name = "chrono" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "regex-syntax 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "semver 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "clippy" +version = "0.0.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "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)", ] @@ -84,7 +120,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "url 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "url 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -99,13 +135,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ctrlc" -version = "1.0.1" -source = "git+https://github.com/tomusdrw/rust-ctrlc.git#d8751b66b31d9698cbb11f8ef37155a8211a0683" +version = "1.1.1" +source = "git+https://github.com/tomusdrw/rust-ctrlc.git#f4927770f89eca80ec250911eea3adcbf579ac48" dependencies = [ "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.5 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "daemonize" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "deque" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -113,19 +164,11 @@ name = "docopt" version = "0.6.78" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "regex 0.1.51 (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)", ] -[[package]] -name = "docopt_macros" -version = "0.6.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "elastic-array" version = "0.4.0" @@ -137,105 +180,151 @@ 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.51 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.58 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "eth-secp256k1" version = "0.5.4" -source = "git+https://github.com/arkpar/rust-secp256k1.git#321e6c22a83606d1875f89cb61c9cb37c7d249ae" +source = "git+https://github.com/ethcore/rust-secp256k1#b6fdd43bbcf6d46adb72a92dd1632a0fc834cbf5" dependencies = [ - "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (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)", - "serde 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ethash" -version = "0.1.0" +version = "1.1.0" dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lru-cache 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "primal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.1.0", ] [[package]] name = "ethcore" -version = "0.9.0" +version = "1.1.0" dependencies = [ - "clippy 0.0.41 (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 0.1.0", - "ethcore-util 0.9.0", - "heapsize 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ethash 1.1.0", + "ethcore-devtools 1.1.0", + "ethcore-util 1.1.0", + "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.10 (registry+https://github.com/rust-lang/crates.io-index)", - "rocksdb 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ethcore-devtools" +version = "1.1.0" +dependencies = [ + "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ethcore-rpc" -version = "0.9.0" +version = "1.1.0" dependencies = [ - "clippy 0.0.41 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 0.9.0", - "ethcore-util 0.9.0", - "ethsync 0.1.0", - "jsonrpc-core 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-http-server 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", + "ethash 1.1.0", + "ethcore 1.1.0", + "ethcore-util 1.1.0", + "ethminer 1.1.0", + "ethsync 1.1.0", + "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.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "target_info 0.1.0 (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)", + "transient-hashmap 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ethcore-util" -version = "0.9.0" +version = "1.1.0" dependencies = [ - "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy 0.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "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.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/arkpar/rust-secp256k1.git)", - "heapsize 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)", + "ethcore-devtools 1.1.0", + "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.8 (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", "lazy_static 0.1.15 (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)", "mio 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "rocksdb 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rocksdb 0.4.3 (git+https://github.com/arkpar/rust-rocksdb.git)", "rust-crypto 0.2.34 (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.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.1.0", - "slab 0.1.4 (git+https://github.com/arkpar/slab.git)", + "slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ethjson" +version = "0.1.0" +dependencies = [ + "ethcore-util 1.1.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.1.0" +dependencies = [ + "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.1.0", + "ethcore-util 1.1.0", + "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 0.3.1 (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)", ] [[package]] name = "ethsync" -version = "0.1.0" +version = "1.1.0" dependencies = [ - "clippy 0.0.41 (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 0.9.0", - "ethcore-util 0.9.0", + "ethcore 1.1.0", + "ethcore-util 1.1.0", + "ethminer 1.1.0", + "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)", @@ -245,25 +334,30 @@ dependencies = [ name = "fdlimit" version = "0.1.0" dependencies = [ - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "gcc" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "glob" -version = "0.2.10" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "hamming" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "heapsize" -version = "0.2.5" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -289,34 +383,34 @@ dependencies = [ "language-tags 0.0.7 (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)", - "num_cpus 0.2.10 (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.2.1 (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)", - "num_cpus 0.2.10 (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.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "url 0.5.5 (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)", ] [[package]] @@ -326,41 +420,43 @@ 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.51 (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)", ] [[package]] name = "itertools" -version = "0.4.8" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "json-tests" version = "0.1.0" dependencies = [ - "glob 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 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)", ] [[package]] name = "jsonrpc-core" -version = "1.1.2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_macros 0.6.13 (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 = "jsonrpc-http-server" -version = "1.1.2" +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 1.1.2 (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]] @@ -368,7 +464,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)", ] @@ -394,28 +490,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "linked-hash-map" -version = "0.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "librocksdb-sys" +version = "0.2.3" +source = "git+https://github.com/arkpar/rust-rocksdb.git#ae44ef33ed1358ffc79aa05ed77839d555daba33" +dependencies = [ + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "log" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lru-cache" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "linked-hash-map 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -428,7 +519,7 @@ name = "memchr" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -437,7 +528,15 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "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]] @@ -449,11 +548,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.21 (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]] @@ -462,20 +561,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.21 (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.21" +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.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.5 (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.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)", ] @@ -498,12 +597,12 @@ dependencies = [ [[package]] name = "nom" -version = "1.2.0" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -512,12 +611,18 @@ dependencies = [ [[package]] name = "num_cpus" -version = "0.2.10" +version = "0.2.11" 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.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "number_prefix" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -526,24 +631,62 @@ version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "quasi" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quasi_codegen" -version = "0.6.0" +name = "primal" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aster 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "primal-check 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "primal-estimate 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "primal-sieve 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "quasi_macros" -version = "0.6.0" +name = "primal-bit" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quasi_codegen 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hamming 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "primal-check" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "primal-estimate" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "primal-sieve" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hamming 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "primal-bit 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "primal-estimate 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quasi" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "syntex_syntax 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quasi_codegen" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "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]] @@ -551,31 +694,53 @@ name = "rand" version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rayon" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex" -version = "0.1.51" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rocksdb" -version = "0.3.0" +version = "0.4.3" +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)", +] + +[[package]] +name = "rpassword" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.1.12 (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)", + "termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -583,7 +748,7 @@ name = "rust-crypto" version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.1.12 (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)", @@ -597,7 +762,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rustc_version" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", @@ -610,52 +775,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "semver" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "nom 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nom 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde" -version = "0.6.13" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "serde_codegen" -version = "0.6.13" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aster 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi_macros 0.6.0 (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]] name = "serde_json" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_macros" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde_codegen 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "sha3" version = "0.1.0" dependencies = [ - "gcc 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -663,11 +827,6 @@ name = "slab" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "slab" -version = "0.1.4" -source = "git+https://github.com/arkpar/slab.git#3c9284e1f010e394c9d0359b27464e8fb5c87bf0" - [[package]] name = "solicit" version = "0.4.4" @@ -682,19 +841,57 @@ name = "strsim" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "syntex" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "syntex_syntax 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syntex_syntax" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "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)", + "term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "target_info" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "term" +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.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termios" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "time" version = "0.1.34" 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.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.5 (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.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -702,11 +899,27 @@ 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" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "transient-hashmap" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "typeable" version = "0.1.2" @@ -714,10 +927,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicase" -version = "1.2.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc_version 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -733,6 +946,11 @@ name = "unicode-normalization" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-xid" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "url" version = "0.2.38" @@ -745,7 +963,7 @@ dependencies = [ [[package]] name = "url" -version = "0.5.5" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -769,9 +987,18 @@ dependencies = [ "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "vergen" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "blastfig 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -784,7 +1011,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)", ] @@ -793,7 +1020,7 @@ name = "xml-rs" version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index ca2ad9c6c..f281cb854 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,29 +1,45 @@ [package] description = "Ethcore client." name = "parity" -version = "0.9.0" +version = "1.1.0" license = "GPL-3.0" authors = ["Ethcore "] +build = "build.rs" + +[build-dependencies] +rustc_version = "0.1" [dependencies] log = "0.3" env_logger = "0.3" rustc-serialize = "0.3" docopt = "0.6" -docopt_macros = "0.6" +time = "0.1" ctrlc = { git = "https://github.com/tomusdrw/rust-ctrlc.git" } -clippy = "0.0.41" -ethcore-util = { path = "util" } -ethcore = { path = "ethcore" } -ethsync = { path = "sync" } -ethcore-rpc = { path = "rpc", optional = true } fdlimit = { path = "util/fdlimit" } -target_info = "0.1" +daemonize = "0.2" +num_cpus = "0.2" +number_prefix = "0.2" +rpassword = "0.1" +clippy = { version = "0.0.54", optional = true } +ethcore = { path = "ethcore" } +ethcore-util = { path = "util" } +ethsync = { path = "sync" } +ethminer = { path = "miner" } +ethcore-devtools = { path = "devtools" } +ethcore-rpc = { path = "rpc", optional = true } [features] default = ["rpc"] rpc = ["ethcore-rpc"] +dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethminer/dev"] +travis-beta = ["ethcore/json-tests"] +travis-nightly = ["ethcore/json-tests", "dev"] [[bin]] path = "parity/main.rs" name = "parity" + +[profile.release] +debug = false +lto = false diff --git a/README.md b/README.md index 2ffb28f45..7aa5e8858 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ethcore -[![Build Status][travis-image]][travis-url] [![Coverage Status][coveralls-image]][coveralls-url] [![Join the chat at https://gitter.im/trogdoro/xiki][gitter-image]][gitter-url] +[![Build Status][travis-image]][travis-url] [![Coverage Status][coveralls-image]][coveralls-url] [![Join the chat at https://gitter.im/trogdoro/xiki][gitter-image]][gitter-url] [![GPLv3][license-image]][license-url] [travis-image]: https://travis-ci.org/ethcore/parity.svg?branch=master [travis-url]: https://travis-ci.org/ethcore/parity @@ -8,70 +8,33 @@ [coveralls-url]: https://coveralls.io/github/ethcore/parity?branch=master [gitter-image]: https://badges.gitter.im/Join%20Chat.svg [gitter-url]: https://gitter.im/ethcore/parity?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge +[license-image]: https://img.shields.io/badge/license-GPL%20v3-green.svg +[license-url]: http://www.gnu.org/licenses/gpl-3.0.en.html [Documentation](http://ethcore.github.io/parity/ethcore/index.html) ### Building from source -##### Ubuntu 14.04, 15.04, 15.10 +First (if you don't already have it) get multirust: +- Linux: ```bash -# install rocksdb -add-apt-repository ppa:ethcore/ethcore -apt-get update -apt-get install -y --force-yes librocksdb-dev - -# install multirust -curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes - -# install nightly and make it default -multirust update nightly -multirust default nightly - -# download and build parity -git clone https://github.com/ethcore/parity -cd parity -cargo build --release +curl -sf https://raw.githubusercontent.com/brson/multirust/master/quick-install.sh | sudo sh -s -- --yes ``` -##### Other Linux - +- OSX with Homebrew: ```bash -# install rocksdb -git clone --tag v4.1 --depth=1 https://github.com/facebook/rocksdb.git -cd rocksdb -make shared_lib -sudo cp -a librocksdb.so* /usr/lib -sudo ldconfig -cd .. - -# install rust nightly -curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sudo sh -s -- --yes - -# install nightly and make it default -sudo multirust update nightly -sudo multirust default nightly - -# download and build parity -git clone https://github.com/ethcore/parity -cd parity -cargo build --release +brew update && brew install multirust +multirust default stable ``` -##### OSX with Homebrew +Then, download and build Parity: ```bash -# install rocksdb && multirust -brew update -brew install rocksdb -brew install multirust - -# install nightly and make it default -multirust update nightly && multirust default nightly - -# download and build parity +# download Parity code git clone https://github.com/ethcore/parity cd parity + +# build in release mode cargo build --release ``` - diff --git a/build.rs b/build.rs new file mode 100644 index 000000000..41b9a1b3e --- /dev/null +++ b/build.rs @@ -0,0 +1,25 @@ +// 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_version; + +use rustc_version::{version_meta, Channel}; + +fn main() { + if let Channel::Nightly = version_meta().channel { + println!("cargo:rustc-cfg=nightly"); + } +} diff --git a/cov.sh b/cov.sh index a1fa29e46..d60ef223d 100755 --- a/cov.sh +++ b/cov.sh @@ -15,12 +15,23 @@ if ! type kcov > /dev/null; then exit 1 fi -cargo test -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity --no-run || exit $? +cargo test \ + -p ethash \ + -p ethcore-util \ + -p ethcore \ + -p ethsync \ + -p ethcore-rpc \ + -p parity \ + -p ethminer \ + --no-run || exit $? rm -rf target/coverage mkdir -p target/coverage -kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests --include-pattern src --verify target/coverage target/debug/deps/ethcore-* -kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests --include-pattern src --verify target/coverage target/debug/deps/ethash-* -kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests --include-pattern src --verify target/coverage target/debug/deps/ethcore_util-* -kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests --include-pattern src --verify target/coverage target/debug/deps/ethsync-* -kcov --exclude-pattern ~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests --include-pattern src --verify target/coverage target/debug/deps/ethcore_rpc-* + +EXCLUDE="~/.multirust,rocksdb,secp256k1,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests" +kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethcore-* +kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethash-* +kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethcore_util-* +kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethsync-* +kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethcore_rpc-* +kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethminer-* xdg-open target/coverage/index.html diff --git a/devtools/Cargo.toml b/devtools/Cargo.toml new file mode 100644 index 000000000..19178fbfe --- /dev/null +++ b/devtools/Cargo.toml @@ -0,0 +1,16 @@ +[package] +description = "Ethcore development/test/build tools" +homepage = "http://ethcore.io" +license = "GPL-3.0" +name = "ethcore-devtools" +version = "1.1.0" +authors = ["Ethcore "] + +[dependencies] +rand = "0.3" + +[features] + +[lib] +path = "src/lib.rs" +test = true diff --git a/devtools/README.md b/devtools/README.md new file mode 100644 index 000000000..5d5144689 --- /dev/null +++ b/devtools/README.md @@ -0,0 +1 @@ +# ethcore dev tools diff --git a/devtools/src/lib.rs b/devtools/src/lib.rs new file mode 100644 index 000000000..f310cca30 --- /dev/null +++ b/devtools/src/lib.rs @@ -0,0 +1,24 @@ +// 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 . + +//! dev-tools + + +extern crate rand; + +pub mod random_path; + +pub use random_path::*; diff --git a/devtools/src/random_path.rs b/devtools/src/random_path.rs new file mode 100644 index 000000000..b037867fa --- /dev/null +++ b/devtools/src/random_path.rs @@ -0,0 +1,89 @@ +// 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 . + +//! Random path + +use std::path::*; +use std::fs; +use std::env; +use rand::random; + +pub struct RandomTempPath { + path: PathBuf +} + +pub fn random_filename() -> String { + (0..8).map(|_| ((random::() * 26.0) as u8 + 97) as char).collect() +} + +impl RandomTempPath { + pub fn new() -> RandomTempPath { + let mut dir = env::temp_dir(); + dir.push(random_filename()); + RandomTempPath { + path: dir.clone() + } + } + + pub fn create_dir() -> RandomTempPath { + let mut dir = env::temp_dir(); + dir.push(random_filename()); + fs::create_dir_all(dir.as_path()).unwrap(); + RandomTempPath { + path: dir.clone() + } + } + + pub fn as_path(&self) -> &PathBuf { + &self.path + } + + pub fn as_str(&self) -> &str { + self.path.to_str().unwrap() + } +} + +impl Drop for RandomTempPath { + fn drop(&mut self) { + if let Err(e) = fs::remove_dir_all(self.as_path()) { + panic!("failed to remove temp directory, probably something failed to destroyed ({})", e); + } + } +} + +#[test] +fn creates_dir() { + let temp = RandomTempPath::create_dir(); + assert!(fs::metadata(temp.as_path()).unwrap().is_dir()); +} + +#[test] +fn destroys_dir() { + let path_buf = { + let temp = RandomTempPath::create_dir(); + assert!(fs::metadata(temp.as_path()).unwrap().is_dir()); + let path_buf = temp.as_path().to_path_buf(); + path_buf + }; + + assert!(fs::metadata(&path_buf).is_err()); +} + +#[test] +fn provides_random() { + let temp = RandomTempPath::create_dir(); + assert!(temp.as_path().to_str().is_some()); +} diff --git a/doc.sh b/doc.sh index 2fd5ac20f..a5e5e2e13 100755 --- a/doc.sh +++ b/doc.sh @@ -1,4 +1,11 @@ #!/bin/sh # generate documentation only for partiy and ethcore libraries -cargo doc --no-deps --verbose -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity +cargo doc --no-deps --verbose \ + -p ethash \ + -p ethcore-util \ + -p ethcore \ + -p ethsync \ + -p ethcore-rpc \ + -p parity \ + -p ethminer diff --git a/docker/ubuntu-dev/Dockerfile b/docker/ubuntu-dev/Dockerfile index 8b016e6fd..05e8dfe8f 100644 --- a/docker/ubuntu-dev/Dockerfile +++ b/docker/ubuntu-dev/Dockerfile @@ -8,8 +8,8 @@ RUN apt-get update && \ # add-apt-repository software-properties-common \ curl \ - gcc \ - wget \ + g++ \ + wget \ git \ # evmjit dependencies zlib1g-dev \ @@ -18,9 +18,8 @@ RUN apt-get update && \ # cmake, llvm and rocksdb ppas. then update ppas RUN add-apt-repository -y "ppa:george-edison55/cmake-3.x" && \ add-apt-repository "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main" && \ - add-apt-repository "deb http://ppa.launchpad.net/giskou/librocksdb/ubuntu trusty main" && \ apt-get update && \ - apt-get install -y --force-yes cmake llvm-3.7-dev librocksdb + apt-get install -y --force-yes cmake llvm-3.7-dev # install evmjit RUN git clone https://github.com/debris/evmjit && \ @@ -31,9 +30,6 @@ RUN git clone https://github.com/debris/evmjit && \ # install multirust RUN curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes -# install nightly and make it default -RUN multirust update nightly && multirust default nightly - # export rust LIBRARY_PATH ENV LIBRARY_PATH /usr/local/lib diff --git a/docker/ubuntu-jit/Dockerfile b/docker/ubuntu-jit/Dockerfile index 90ce531be..138882d2b 100644 --- a/docker/ubuntu-jit/Dockerfile +++ b/docker/ubuntu-jit/Dockerfile @@ -8,9 +8,9 @@ RUN apt-get update && \ # add-apt-repository software-properties-common \ curl \ - wget \ + wget \ git \ - gcc \ + g++ \ # evmjit dependencies zlib1g-dev \ libedit-dev @@ -18,9 +18,8 @@ RUN apt-get update && \ # cmake, llvm and rocksdb ppas. then update ppas RUN add-apt-repository -y "ppa:george-edison55/cmake-3.x" && \ add-apt-repository "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.7 main" && \ - add-apt-repository "deb http://ppa.launchpad.net/giskou/librocksdb/ubuntu trusty main" && \ apt-get update && \ - apt-get install -y --force-yes cmake llvm-3.7-dev librocksdb + apt-get install -y --force-yes cmake llvm-3.7-dev # install evmjit RUN git clone https://github.com/debris/evmjit && \ @@ -31,9 +30,6 @@ RUN git clone https://github.com/debris/evmjit && \ # install multirust RUN curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes -# install nightly and make it default -RUN multirust update nightly && multirust default nightly - # export rust LIBRARY_PATH ENV LIBRARY_PATH /usr/local/lib @@ -41,7 +37,6 @@ ENV LIBRARY_PATH /usr/local/lib ENV RUST_BACKTRACE 1 # build parity -# TODO: add jit feature RUN git clone https://github.com/ethcore/parity && \ cd parity && \ - cargo install --features rpc + cargo build --release --features ethcore/jit diff --git a/docker/ubuntu/Dockerfile b/docker/ubuntu/Dockerfile index 812e66e9e..38c628d0e 100644 --- a/docker/ubuntu/Dockerfile +++ b/docker/ubuntu/Dockerfile @@ -3,23 +3,14 @@ FROM ubuntu:14.04 # install tools and dependencies RUN apt-get update && \ apt-get install -y \ - gcc \ + g++ \ curl \ git \ - # add-apt-repository - software-properties-common - -# rocksdb ppas. then update ppas -RUN add-apt-repository "deb http://ppa.launchpad.net/giskou/librocksdb/ubuntu trusty main" && \ - apt-get update && \ - apt-get install -y --force-yes librocksdb + make # install multirust RUN curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes -# install nightly and make it default -RUN multirust update nightly && multirust default nightly - # export rust LIBRARY_PATH ENV LIBRARY_PATH /usr/local/lib @@ -29,4 +20,4 @@ ENV RUST_BACKTRACE 1 # build parity RUN git clone https://github.com/ethcore/parity && \ cd parity && \ - cargo install --features rpc + cargo build --release diff --git a/ethash/Cargo.toml b/ethash/Cargo.toml index 4c0b3d65e..70d08249c 100644 --- a/ethash/Cargo.toml +++ b/ethash/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "ethash" -version = "0.1.0" +version = "1.1.0" authors = ["arkpar Self { + fn default() -> Self { Node { bytes: [0u8; NODE_BYTES] } } } @@ -109,7 +113,7 @@ impl Light { pub fn from_file(block_number: u64) -> io::Result { let path = Light::file_path(block_number); let mut file = try!(File::open(path)); - + let cache_size = get_cache_size(block_number); if try!(file.metadata()).len() != cache_size as u64 { return Err(io::Error::new(io::ErrorKind::Other, "Cache file size mismatch")); @@ -129,10 +133,10 @@ impl Light { let path = Light::file_path(self.block_number); try!(fs::create_dir_all(path.parent().unwrap())); let mut file = try!(File::create(path)); - + let cache_size = self.cache.len() * NODE_BYTES; let buf = unsafe { slice::from_raw_parts(self.cache.as_ptr() as *const u8, cache_size) }; - try!(file.write(buf)); + try!(file.write(buf)); Ok(()) } } @@ -149,18 +153,27 @@ fn sha3_512(input: &[u8], output: &mut [u8]) { #[inline] fn get_cache_size(block_number: u64) -> usize { - assert!(block_number / ETHASH_EPOCH_LENGTH < 2048); - return CACHE_SIZES[(block_number / ETHASH_EPOCH_LENGTH) as usize] as usize; + let mut sz: u64 = CACHE_BYTES_INIT + CACHE_BYTES_GROWTH * (block_number / ETHASH_EPOCH_LENGTH); + sz = sz - NODE_BYTES as u64; + while !is_prime(sz / NODE_BYTES as u64) { + sz = sz - 2 * NODE_BYTES as u64; + } + sz as usize } #[inline] fn get_data_size(block_number: u64) -> usize { - assert!(block_number / ETHASH_EPOCH_LENGTH < 2048); - return DAG_SIZES[(block_number / ETHASH_EPOCH_LENGTH) as usize] as usize; + let mut sz: u64 = DATASET_BYTES_INIT + DATASET_BYTES_GROWTH * (block_number / ETHASH_EPOCH_LENGTH); + sz = sz - ETHASH_MIX_BYTES as u64; + while !is_prime(sz / ETHASH_MIX_BYTES as u64) { + sz = sz - 2 * ETHASH_MIX_BYTES as u64; + } + sz as usize } #[inline] -fn get_seedhash(block_number: u64) -> H256 { +/// Given the `block_number`, determine the seed hash for Ethash. +pub fn get_seedhash(block_number: u64) -> H256 { let epochs = block_number / ETHASH_EPOCH_LENGTH; let mut ret: H256 = [0u8; 32]; for _ in 0..epochs { @@ -289,7 +302,7 @@ fn light_new(block_number: u64) -> Light { for i in 1..num_nodes { sha3::sha3_512(nodes.get_unchecked_mut(i).bytes.as_mut_ptr(), NODE_BYTES, nodes.get_unchecked(i - 1).bytes.as_ptr(), NODE_BYTES); } - + for _ in 0..ETHASH_CACHE_ROUNDS { for i in 0..num_nodes { let idx = *nodes.get_unchecked_mut(i).as_words().get_unchecked(0) as usize % num_nodes; @@ -321,10 +334,35 @@ fn to_hex(bytes: &[u8]) -> String { } } +#[test] +fn test_get_cache_size() { + // https://github.com/ethereum/wiki/wiki/Ethash/ef6b93f9596746a088ea95d01ca2778be43ae68f#data-sizes + assert_eq!(16776896usize, get_cache_size(0)); + assert_eq!(16776896usize, get_cache_size(1)); + assert_eq!(16776896usize, get_cache_size(ETHASH_EPOCH_LENGTH - 1)); + assert_eq!(16907456usize, get_cache_size(ETHASH_EPOCH_LENGTH)); + assert_eq!(16907456usize, get_cache_size(ETHASH_EPOCH_LENGTH + 1)); + assert_eq!(284950208usize, get_cache_size(2046 * ETHASH_EPOCH_LENGTH)); + assert_eq!(285081536usize, get_cache_size(2047 * ETHASH_EPOCH_LENGTH)); + assert_eq!(285081536usize, get_cache_size(2048 * ETHASH_EPOCH_LENGTH - 1)); +} + +#[test] +fn test_get_data_size() { + // https://github.com/ethereum/wiki/wiki/Ethash/ef6b93f9596746a088ea95d01ca2778be43ae68f#data-sizes + assert_eq!(1073739904usize, get_data_size(0)); + assert_eq!(1073739904usize, get_data_size(1)); + assert_eq!(1073739904usize, get_data_size(ETHASH_EPOCH_LENGTH - 1)); + assert_eq!(1082130304usize, get_data_size(ETHASH_EPOCH_LENGTH)); + assert_eq!(1082130304usize, get_data_size(ETHASH_EPOCH_LENGTH + 1)); + assert_eq!(18236833408usize, get_data_size(2046 * ETHASH_EPOCH_LENGTH)); + assert_eq!(18245220736usize, get_data_size(2047 * ETHASH_EPOCH_LENGTH)); +} + #[test] fn test_difficulty_test() { let hash = [0xf5, 0x7e, 0x6f, 0x3a, 0xcf, 0xc0, 0xdd, 0x4b, 0x5b, 0xf2, 0xbe, 0xe4, 0x0a, 0xb3, 0x35, 0x8a, 0xa6, 0x87, 0x73, 0xa8, 0xd0, 0x9f, 0x5e, 0x59, 0x5e, 0xab, 0x55, 0x94, 0x05, 0x52, 0x7d, 0x72]; - let mix_hash = [0x1f, 0xff, 0x04, 0xce, 0xc9, 0x41, 0x73, 0xfd, 0x59, 0x1e, 0x3d, 0x89, 0x60, 0xce, 0x6b, 0xdf, 0x8b, 0x19, 0x71, 0x04, 0x8c, 0x71, 0xff, 0x93, 0x7b, 0xb2, 0xd3, 0x2a, 0x64, 0x31, 0xab, 0x6d ]; + let mix_hash = [0x1f, 0xff, 0x04, 0xce, 0xc9, 0x41, 0x73, 0xfd, 0x59, 0x1e, 0x3d, 0x89, 0x60, 0xce, 0x6b, 0xdf, 0x8b, 0x19, 0x71, 0x04, 0x8c, 0x71, 0xff, 0x93, 0x7b, 0xb2, 0xd3, 0x2a, 0x64, 0x31, 0xab, 0x6d ]; let nonce = 0xd7b3ac70a301a249; let boundary_good = [0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3e, 0x9b, 0x6c, 0x69, 0xbc, 0x2c, 0xe2, 0xa2, 0x4a, 0x8e, 0x95, 0x69, 0xef, 0xc7, 0xd7, 0x1b, 0x33, 0x35, 0xdf, 0x36, 0x8c, 0x9a, 0xe9, 0x7e, 0x53, 0x84]; assert_eq!(quick_get_difficulty(&hash, nonce, &mix_hash)[..], boundary_good[..]); @@ -335,7 +373,7 @@ fn test_difficulty_test() { #[test] fn test_light_compute() { let hash = [0xf5, 0x7e, 0x6f, 0x3a, 0xcf, 0xc0, 0xdd, 0x4b, 0x5b, 0xf2, 0xbe, 0xe4, 0x0a, 0xb3, 0x35, 0x8a, 0xa6, 0x87, 0x73, 0xa8, 0xd0, 0x9f, 0x5e, 0x59, 0x5e, 0xab, 0x55, 0x94, 0x05, 0x52, 0x7d, 0x72]; - let mix_hash = [0x1f, 0xff, 0x04, 0xce, 0xc9, 0x41, 0x73, 0xfd, 0x59, 0x1e, 0x3d, 0x89, 0x60, 0xce, 0x6b, 0xdf, 0x8b, 0x19, 0x71, 0x04, 0x8c, 0x71, 0xff, 0x93, 0x7b, 0xb2, 0xd3, 0x2a, 0x64, 0x31, 0xab, 0x6d ]; + let mix_hash = [0x1f, 0xff, 0x04, 0xce, 0xc9, 0x41, 0x73, 0xfd, 0x59, 0x1e, 0x3d, 0x89, 0x60, 0xce, 0x6b, 0xdf, 0x8b, 0x19, 0x71, 0x04, 0x8c, 0x71, 0xff, 0x93, 0x7b, 0xb2, 0xd3, 0x2a, 0x64, 0x31, 0xab, 0x6d ]; let boundary = [0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3e, 0x9b, 0x6c, 0x69, 0xbc, 0x2c, 0xe2, 0xa2, 0x4a, 0x8e, 0x95, 0x69, 0xef, 0xc7, 0xd7, 0x1b, 0x33, 0x35, 0xdf, 0x36, 0x8c, 0x9a, 0xe9, 0x7e, 0x53, 0x84]; let nonce = 0xd7b3ac70a301a249; // difficulty = 0x085657254bd9u64; diff --git a/ethash/src/lib.rs b/ethash/src/lib.rs index 4c6b8639f..982f7129b 100644 --- a/ethash/src/lib.rs +++ b/ethash/src/lib.rs @@ -16,29 +16,40 @@ //! Ethash implementation //! See https://github.com/ethereum/wiki/wiki/Ethash +extern crate primal; extern crate sha3; -extern crate lru_cache; #[macro_use] extern crate log; -mod sizes; mod compute; -use lru_cache::LruCache; +use std::mem; use compute::Light; -pub use compute::{quick_get_difficulty, H256, ProofOfWork, ETHASH_EPOCH_LENGTH}; +pub use compute::{get_seedhash, quick_get_difficulty, H256, ProofOfWork, ETHASH_EPOCH_LENGTH}; use std::sync::{Arc, Mutex}; -/// Lighy/Full cache manager +struct LightCache { + recent_epoch: Option, + recent: Option>, + prev_epoch: Option, + prev: Option>, +} + +/// Light/Full cache manager. pub struct EthashManager { - lights: Mutex>> + cache: Mutex, } impl EthashManager { /// Create a new new instance of ethash manager pub fn new() -> EthashManager { - EthashManager { - lights: Mutex::new(LruCache::new(2)) + EthashManager { + cache: Mutex::new(LightCache { + recent_epoch: None, + recent: None, + prev_epoch: None, + prev: None, + }), } } @@ -50,12 +61,28 @@ impl EthashManager { pub fn compute_light(&self, block_number: u64, header_hash: &H256, nonce: u64) -> ProofOfWork { let epoch = block_number / ETHASH_EPOCH_LENGTH; let light = { - let mut lights = self.lights.lock().unwrap(); - match lights.get_mut(&epoch).map(|l| l.clone()) { + let mut lights = self.cache.lock().unwrap(); + let light = match lights.recent_epoch.clone() { + Some(ref e) if *e == epoch => lights.recent.clone(), + _ => match lights.prev_epoch.clone() { + Some(e) if e == epoch => { + // swap + let t = lights.prev_epoch; + lights.prev_epoch = lights.recent_epoch; + lights.recent_epoch = t; + let t = lights.prev.clone(); + lights.prev = lights.recent.clone(); + lights.recent = t; + lights.recent.clone() + } + _ => None, + } + }; + match light { None => { let light = match Light::from_file(block_number) { Ok(light) => Arc::new(light), - Err(e) => { + Err(e) => { debug!("Light cache file not found for {}:{}", block_number, e); let light = Light::new(block_number); if let Err(e) = light.to_file() { @@ -64,7 +91,8 @@ impl EthashManager { Arc::new(light) } }; - lights.insert(epoch, light.clone()); + lights.prev_epoch = mem::replace(&mut lights.recent_epoch, Some(epoch)); + lights.prev = mem::replace(&mut lights.recent, Some(light.clone())); light } Some(light) => light @@ -73,3 +101,19 @@ impl EthashManager { light.compute(header_hash, nonce) } } + +#[test] +fn test_lru() { + let ethash = EthashManager::new(); + let hash = [0u8; 32]; + ethash.compute_light(1, &hash, 1); + ethash.compute_light(50000, &hash, 1); + assert_eq!(ethash.cache.lock().unwrap().recent_epoch.unwrap(), 1); + assert_eq!(ethash.cache.lock().unwrap().prev_epoch.unwrap(), 0); + ethash.compute_light(1, &hash, 1); + assert_eq!(ethash.cache.lock().unwrap().recent_epoch.unwrap(), 0); + assert_eq!(ethash.cache.lock().unwrap().prev_epoch.unwrap(), 1); + ethash.compute_light(70000, &hash, 1); + assert_eq!(ethash.cache.lock().unwrap().recent_epoch.unwrap(), 2); + assert_eq!(ethash.cache.lock().unwrap().prev_epoch.unwrap(), 0); +} diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 90d147a02..5b613fdb2 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -3,27 +3,30 @@ description = "Ethcore library" homepage = "http://ethcore.io" license = "GPL-3.0" name = "ethcore" -version = "0.9.0" +version = "1.1.0" authors = ["Ethcore "] [dependencies] log = "0.3" env_logger = "0.3" rustc-serialize = "0.3" -rocksdb = "0.3" -heapsize = "0.2.0" +heapsize = "0.3" rust-crypto = "0.2.34" time = "0.1" ethcore-util = { path = "../util" } evmjit = { path = "../evmjit", optional = true } ethash = { path = "../ethash" } num_cpus = "0.2" -clippy = "0.0.41" +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"] evm-debug = [] json-tests = [] test-heavy = [] +dev = ["clippy"] +default = [] diff --git a/ethcore/res/ethereum/frontier.json b/ethcore/res/ethereum/frontier.json index 6e31a2fce..8f9209179 100644 --- a/ethcore/res/ethereum/frontier.json +++ b/ethcore/res/ethereum/frontier.json @@ -1,9 +1,9 @@ { - "name": "Frontier", + "name": "Frontier/Homestead", "engineName": "Ethash", "params": { "accountStartNonce": "0x00", - "frontierCompatibilityModeLimit": "0x10c8e0", + "frontierCompatibilityModeLimit": "0x118c30", "maximumExtraDataSize": "0x20", "tieBreakingGas": false, "minGasLimit": "0x1388", @@ -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 553bb8018..376b369c4 100644 --- a/ethcore/res/ethereum/frontier_like_test.json +++ b/ethcore/res/ethereum/frontier_like_test.json @@ -1,9 +1,9 @@ { - "engineName": "Frontier (Test)", + "name": "Frontier (Test)", "engineName": "Ethash", "params": { "accountStartNonce": "0x00", - "frontierCompatibilityModeLimit": "0x10c8e0", + "frontierCompatibilityModeLimit": "0x118c30", "maximumExtraDataSize": "0x20", "tieBreakingGas": false, "minGasLimit": "0x1388", @@ -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 0d0c2489d..2cf4785db 100644 --- a/ethcore/res/ethereum/morden.json +++ b/ethcore/res/ethereum/morden.json @@ -3,7 +3,7 @@ "engineName": "Ethash", "params": { "accountStartNonce": "0x0100000", - "frontierCompatibilityModeLimit": "0x10c8e0", + "frontierCompatibilityModeLimit": "0x789b0", "maximumExtraDataSize": "0x20", "tieBreakingGas": false, "minGasLimit": "0x1388", @@ -25,11 +25,14 @@ "extraData": "0x", "gasLimit": "0x2fefd8" }, + "nodes": [ + "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/ethereum/tests b/ethcore/res/ethereum/tests index 3116f85a4..99afe8f5a 160000 --- a/ethcore/res/ethereum/tests +++ b/ethcore/res/ethereum/tests @@ -1 +1 @@ -Subproject commit 3116f85a499ceaf4dfdc46726060fc056e2d7829 +Subproject commit 99afe8f5aad7bca5d0f1b1685390a4dea32d73c3 diff --git a/ethcore/res/null_homestead_morden.json b/ethcore/res/null_homestead_morden.json new file mode 100644 index 000000000..abd3f4de9 --- /dev/null +++ b/ethcore/res/null_homestead_morden.json @@ -0,0 +1,35 @@ +{ + "name": "Morden", + "engineName": "NullEngine", + "params": { + "accountStartNonce": "0x0100000", + "frontierCompatibilityModeLimit": "0x0", + "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" + }, + "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" } + } +} diff --git a/ethcore/res/null_morden.json b/ethcore/res/null_morden.json index 46507ff95..86148d640 100644 --- a/ethcore/res/null_morden.json +++ b/ethcore/res/null_morden.json @@ -3,7 +3,7 @@ "engineName": "NullEngine", "params": { "accountStartNonce": "0x0100000", - "frontierCompatibilityModeLimit": "0xfffa2990", + "frontierCompatibilityModeLimit": "0x789b0", "maximumExtraDataSize": "0x20", "tieBreakingGas": false, "minGasLimit": "0x1388", @@ -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/account.rs b/ethcore/src/account.rs index c36c35232..6901996bc 100644 --- a/ethcore/src/account.rs +++ b/ethcore/src/account.rs @@ -92,10 +92,10 @@ impl Account { /// Create a new contract account. /// NOTE: make sure you use `init_code` on this before `commit`ing. - pub fn new_contract(balance: U256) -> Account { + pub fn new_contract(balance: U256, nonce: U256) -> Account { Account { balance: balance, - nonce: U256::from(0u8), + nonce: nonce, storage_root: SHA3_NULL_RLP, storage_overlay: RefCell::new(HashMap::new()), code_hash: None, @@ -261,7 +261,7 @@ mod tests { let mut db = MemoryDB::new(); let mut db = AccountDBMut::new(&mut db, &Address::new()); let rlp = { - let mut a = Account::new_contract(U256::from(69u8)); + let mut a = Account::new_contract(x!(69), x!(0)); a.set_storage(H256::from(&U256::from(0x00u64)), H256::from(&U256::from(0x1234u64))); a.commit_storage(&mut db); a.init_code(vec![]); @@ -281,7 +281,7 @@ mod tests { let mut db = AccountDBMut::new(&mut db, &Address::new()); let rlp = { - let mut a = Account::new_contract(U256::from(69u8)); + let mut a = Account::new_contract(x!(69), x!(0)); a.init_code(vec![0x55, 0x44, 0xffu8]); a.commit_code(&mut db); a.rlp() @@ -296,7 +296,7 @@ mod tests { #[test] fn commit_storage() { - let mut a = Account::new_contract(U256::from(69u8)); + let mut a = Account::new_contract(x!(69), x!(0)); let mut db = MemoryDB::new(); let mut db = AccountDBMut::new(&mut db, &Address::new()); a.set_storage(x!(0), x!(0x1234)); @@ -307,7 +307,7 @@ mod tests { #[test] fn commit_remove_commit_storage() { - let mut a = Account::new_contract(U256::from(69u8)); + let mut a = Account::new_contract(x!(69), x!(0)); let mut db = MemoryDB::new(); let mut db = AccountDBMut::new(&mut db, &Address::new()); a.set_storage(x!(0), x!(0x1234)); @@ -321,7 +321,7 @@ mod tests { #[test] fn commit_code() { - let mut a = Account::new_contract(U256::from(69u8)); + let mut a = Account::new_contract(x!(69), x!(0)); let mut db = MemoryDB::new(); let mut db = AccountDBMut::new(&mut db, &Address::new()); a.init_code(vec![0x55, 0x44, 0xffu8]); diff --git a/ethcore/src/account_db.rs b/ethcore/src/account_db.rs index e7f1b2bad..f95ec53a1 100644 --- a/ethcore/src/account_db.rs +++ b/ethcore/src/account_db.rs @@ -13,17 +13,14 @@ pub struct AccountDB<'db> { #[inline] fn combine_key<'a>(address: &'a H256, key: &'a H256) -> H256 { - let mut addr_hash = address.sha3(); - // preserve 96 bits of original key for db lookup - addr_hash[0..12].clone_from_slice(&[0u8; 12]); - &addr_hash ^ key + address ^ key } impl<'db> AccountDB<'db> { pub fn new(db: &'db HashDB, address: &Address) -> AccountDB<'db> { AccountDB { db: db, - address: x!(address.clone()), + address: x!(address), } } } @@ -70,7 +67,7 @@ impl<'db> AccountDBMut<'db> { pub fn new(db: &'db mut HashDB, address: &Address) -> AccountDBMut<'db> { AccountDBMut { db: db, - address: x!(address.clone()), + address: x!(address), } } @@ -100,6 +97,9 @@ impl<'db> HashDB for AccountDBMut<'db>{ } fn insert(&mut self, value: &[u8]) -> H256 { + if value == &NULL_RLP { + return SHA3_NULL_RLP.clone(); + } let k = value.sha3(); let ak = combine_key(&self.address, &k); self.db.emplace(ak, value.to_vec()); @@ -107,11 +107,17 @@ impl<'db> HashDB for AccountDBMut<'db>{ } fn emplace(&mut self, key: H256, value: Bytes) { + if key == SHA3_NULL_RLP { + return; + } let key = combine_key(&self.address, &key); self.db.emplace(key, value.to_vec()) } fn kill(&mut self, key: &H256) { + if key == &SHA3_NULL_RLP { + return; + } let key = combine_key(&self.address, key); self.db.kill(&key) } diff --git a/ethcore/src/action_params.rs b/ethcore/src/action_params.rs index 9e2d72c73..fa40d30a0 100644 --- a/ethcore/src/action_params.rs +++ b/ethcore/src/action_params.rs @@ -15,9 +15,7 @@ // along with Parity. If not, see . //! Evm input params. -use util::hash::*; -use util::uint::*; -use util::bytes::*; +use common::*; /// Transaction value #[derive(Clone, Debug)] diff --git a/ethcore/src/basic_types.rs b/ethcore/src/basic_types.rs index 2e9c5d7b9..5f6515c0d 100644 --- a/ethcore/src/basic_types.rs +++ b/ethcore/src/basic_types.rs @@ -24,7 +24,7 @@ pub type LogBloom = H2048; /// Constant 2048-bit datum for 0. Often used as a default. pub static ZERO_LOGBLOOM: LogBloom = H2048([0x00; 256]); -#[allow(enum_variant_names)] +#[cfg_attr(feature="dev", allow(enum_variant_names))] /// Semantic boolean for when a seal/signature is included. pub enum Seal { /// The seal/signature is included. diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index c03417dc1..d700b854f 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -16,15 +16,14 @@ //! Blockchain block. -#![allow(ptr_arg)] // Because of &LastHashes -> &Vec<_> +#![cfg_attr(feature="dev", allow(ptr_arg))] // Because of &LastHashes -> &Vec<_> use common::*; use engine::*; use state::*; -use verification::PreVerifiedBlock; +use verification::PreverifiedBlock; /// A block, encoded as it is on the block chain. -// TODO: rename to Block #[derive(Default, Debug, Clone)] pub struct Block { /// The header of this block. @@ -48,7 +47,7 @@ impl Block { if urlp.at(1).unwrap().iter().find(|i| i.as_val::().is_err()).is_some() { return false; } - + if !urlp.at(2).unwrap().is_list() { return false; } if urlp.at(2).unwrap().iter().find(|i| i.as_val::
().is_err()).is_some() { return false; @@ -61,7 +60,7 @@ impl Block { impl Decodable for Block { fn decode(decoder: &D) -> Result where D: Decoder { if decoder.as_raw().len() != try!(decoder.as_rlp().payload_info()).total() { - return Err(DecoderError::RlpIsTooBig); + return Err(DecoderError::RlpIsTooBig); } let d = decoder.as_rlp(); if d.item_count() != 3 { @@ -76,8 +75,6 @@ impl Decodable for Block { } /// Internal type for a block's common elements. -// TODO: rename to ExecutedBlock -// TODO: use BareBlock #[derive(Debug)] pub struct ExecutedBlock { base: Block, @@ -85,9 +82,10 @@ pub struct ExecutedBlock { receipts: Vec, transactions_set: HashSet, state: State, + traces: Option>, } -/// A set of references to `ExecutedBlock` fields that are publicly accessible. +/// A set of references to `ExecutedBlock` fields that are publicly accessible. pub struct BlockRefMut<'a> { /// Block header. pub header: &'a Header, @@ -99,11 +97,21 @@ pub struct BlockRefMut<'a> { pub receipts: &'a Vec, /// State. pub state: &'a mut State, + /// Traces. + pub traces: &'a Option>, } impl ExecutedBlock { /// Create a new block from the given `state`. - fn new(state: State) -> ExecutedBlock { ExecutedBlock { base: Default::default(), receipts: Default::default(), transactions_set: Default::default(), state: state } } + fn new(state: State, tracing: bool) -> ExecutedBlock { + ExecutedBlock { + base: Default::default(), + receipts: Default::default(), + transactions_set: Default::default(), + state: state, + traces: if tracing {Some(Vec::new())} else {None}, + } + } /// Get a structure containing individual references to all public fields. pub fn fields(&mut self) -> BlockRefMut { @@ -113,6 +121,7 @@ impl ExecutedBlock { uncles: &self.base.uncles, state: &mut self.state, receipts: &self.receipts, + traces: &self.traces, } } } @@ -134,6 +143,9 @@ pub trait IsBlock { /// Get all information on receipts in this block. fn receipts(&self) -> &Vec { &self.block().receipts } + /// Get all information concerning transaction tracing in this block. + fn traces(&self) -> &Option> { &self.block().traces } + /// Get all uncles in this block. fn uncles(&self) -> &Vec
{ &self.block().base.uncles } } @@ -144,20 +156,20 @@ impl IsBlock for ExecutedBlock { /// Block that is ready for transactions to be added. /// -/// It's a bit like a Vec, eccept that whenever a transaction is pushed, we execute it and +/// It's a bit like a Vec, except that whenever a transaction is pushed, we execute it and /// maintain the system `state()`. We also archive execution receipts in preparation for later block creation. -pub struct OpenBlock<'x, 'y> { +pub struct OpenBlock<'x> { block: ExecutedBlock, engine: &'x Engine, - last_hashes: &'y LastHashes, + last_hashes: LastHashes, } /// Just like OpenBlock, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields, /// and collected the uncles. /// -/// There is no function available to push a transaction. If you want that you'll need to `reopen()` it. -pub struct ClosedBlock<'x, 'y> { - open_block: OpenBlock<'x, 'y>, +/// There is no function available to push a transaction. +pub struct ClosedBlock { + block: ExecutedBlock, uncle_bytes: Bytes, } @@ -169,21 +181,23 @@ pub struct SealedBlock { uncle_bytes: Bytes, } -impl<'x, 'y> OpenBlock<'x, 'y> { +impl<'x> OpenBlock<'x> { /// Create a new OpenBlock ready for transaction pushing. - pub fn new<'a, 'b>(engine: &'a Engine, db: JournalDB, parent: &Header, last_hashes: &'b LastHashes, author: Address, extra_data: Bytes) -> OpenBlock<'a, 'b> { + pub fn new(engine: &'x Engine, tracing: bool, db: Box, parent: &Header, last_hashes: LastHashes, author: Address, gas_floor_target: U256, extra_data: Bytes) -> Self { let mut r = OpenBlock { - block: ExecutedBlock::new(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce())), + block: ExecutedBlock::new(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce()), tracing), engine: engine, last_hashes: last_hashes, }; - r.block.base.header.set_number(parent.number() + 1); - r.block.base.header.set_author(author); - r.block.base.header.set_extra_data(extra_data); - r.block.base.header.set_timestamp_now(); + r.block.base.header.parent_hash = parent.hash(); + r.block.base.header.number = parent.number + 1; + r.block.base.header.author = author; + r.block.base.header.set_timestamp_now(parent.timestamp()); + r.block.base.header.extra_data = extra_data; + r.block.base.header.note_dirty(); - engine.populate_from_parent(&mut r.block.base.header, parent); + engine.populate_from_parent(&mut r.block.base.header, parent, gas_floor_target); engine.on_new_block(&mut r.block); r } @@ -218,8 +232,8 @@ impl<'x, 'y> OpenBlock<'x, 'y> { /// NOTE Will check chain constraints and the uncle number but will NOT check /// that the header itself is actually valid. pub fn push_uncle(&mut self, valid_uncle_header: Header) -> Result<(), BlockError> { - if self.block.base.uncles.len() >= self.engine.maximum_uncle_count() { - return Err(BlockError::TooManyUncles(OutOfBounds{min: None, max: Some(self.engine.maximum_uncle_count()), found: self.block.base.uncles.len()})); + if self.block.base.uncles.len() + 1 > self.engine.maximum_uncle_count() { + return Err(BlockError::TooManyUncles(OutOfBounds{min: None, max: Some(self.engine.maximum_uncle_count()), found: self.block.base.uncles.len() + 1})); } // TODO: check number // TODO: check not a direct ancestor (use last_hashes for that) @@ -247,11 +261,13 @@ impl<'x, 'y> OpenBlock<'x, 'y> { pub fn push_transaction(&mut self, t: SignedTransaction, h: Option) -> Result<&Receipt, Error> { let env_info = self.env_info(); // info!("env_info says gas_used={}", env_info.gas_used); - match self.block.state.apply(&env_info, self.engine, &t) { - Ok(receipt) => { + match self.block.state.apply(&env_info, self.engine, &t, self.block.traces.is_some()) { + Ok(outcome) => { self.block.transactions_set.insert(h.unwrap_or_else(||t.hash())); self.block.base.transactions.push(t); - self.block.receipts.push(receipt); + let t = outcome.trace; + self.block.traces.as_mut().map(|traces| traces.push(t.expect("self.block.traces.is_some(): so we must be tracing: qed"))); + self.block.receipts.push(outcome.receipt); Ok(&self.block.receipts.last().unwrap()) } Err(x) => Err(From::from(x)) @@ -259,58 +275,63 @@ impl<'x, 'y> OpenBlock<'x, 'y> { } /// Turn this into a `ClosedBlock`. A BlockChain must be provided in order to figure out the uncles. - pub fn close(self) -> ClosedBlock<'x, 'y> { + pub fn close(self) -> ClosedBlock { let mut s = self; s.engine.on_close_block(&mut s.block); s.block.base.header.transactions_root = ordered_trie_root(s.block.base.transactions.iter().map(|ref e| e.rlp_bytes().to_vec()).collect()); - let uncle_bytes = s.block.base.uncles.iter().fold(RlpStream::new_list(s.block.base.uncles.len()), |mut s, u| {s.append(&u.rlp(Seal::With)); s} ).out(); + let uncle_bytes = s.block.base.uncles.iter().fold(RlpStream::new_list(s.block.base.uncles.len()), |mut s, u| {s.append_raw(&u.rlp(Seal::With), 1); s} ).out(); s.block.base.header.uncles_hash = uncle_bytes.sha3(); s.block.base.header.state_root = s.block.state.root().clone(); s.block.base.header.receipts_root = ordered_trie_root(s.block.receipts.iter().map(|ref r| r.rlp_bytes().to_vec()).collect()); - s.block.base.header.log_bloom = s.block.receipts.iter().fold(LogBloom::zero(), |mut b, r| {b |= &r.log_bloom; b}); + s.block.base.header.log_bloom = s.block.receipts.iter().fold(LogBloom::zero(), |mut b, r| {b = &b | &r.log_bloom; b}); //TODO: use |= operator s.block.base.header.gas_used = s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used); s.block.base.header.note_dirty(); - ClosedBlock::new(s, uncle_bytes) - } -} - -impl<'x, 'y> IsBlock for OpenBlock<'x, 'y> { - fn block(&self) -> &ExecutedBlock { &self.block } -} - -impl<'x, 'y> IsBlock for ClosedBlock<'x, 'y> { - fn block(&self) -> &ExecutedBlock { &self.open_block.block } -} - -impl<'x, 'y> ClosedBlock<'x, 'y> { - fn new<'a, 'b>(open_block: OpenBlock<'a, 'b>, uncle_bytes: Bytes) -> ClosedBlock<'a, 'b> { ClosedBlock { - open_block: open_block, + block: s.block, uncle_bytes: uncle_bytes, } } +} +impl<'x> IsBlock for OpenBlock<'x> { + fn block(&self) -> &ExecutedBlock { &self.block } +} + +impl<'x> IsBlock for ClosedBlock { + fn block(&self) -> &ExecutedBlock { &self.block } +} + +impl ClosedBlock { /// Get the hash of the header without seal arguments. pub fn hash(&self) -> H256 { self.header().rlp_sha3(Seal::Without) } /// Provide a valid seal in order to turn this into a `SealedBlock`. /// /// NOTE: This does not check the validity of `seal` with the engine. - pub fn seal(self, seal: Vec) -> Result { + pub fn seal(self, engine: &Engine, seal: Vec) -> Result { let mut s = self; - if seal.len() != s.open_block.engine.seal_fields() { - return Err(BlockError::InvalidSealArity(Mismatch{expected: s.open_block.engine.seal_fields(), found: seal.len()})); + if seal.len() != engine.seal_fields() { + return Err(BlockError::InvalidSealArity(Mismatch{expected: engine.seal_fields(), found: seal.len()})); } - s.open_block.block.base.header.set_seal(seal); - Ok(SealedBlock { block: s.open_block.block, uncle_bytes: s.uncle_bytes }) + s.block.base.header.set_seal(seal); + Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }) } - /// Turn this back into an `OpenBlock`. - pub fn reopen(self) -> OpenBlock<'x, 'y> { self.open_block } + /// Provide a valid seal in order to turn this into a `SealedBlock`. + /// This does check the validity of `seal` with the engine. + /// Returns the `ClosedBlock` back again if the seal is no good. + pub fn try_seal(self, engine: &Engine, seal: Vec) -> Result { + let mut s = self; + s.block.base.header.set_seal(seal); + match engine.verify_block_seal(&s.block.base.header) { + Err(_) => Err(s), + _ => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }), + } + } /// Drop this object and return the underlieing database. - pub fn drain(self) -> JournalDB { self.open_block.block.state.drop().1 } + pub fn drain(self) -> Box { self.block.state.drop().1 } } impl SealedBlock { @@ -324,7 +345,7 @@ impl SealedBlock { } /// Drop this object and return the underlieing database. - pub fn drain(self) -> JournalDB { self.block.state.drop().1 } + pub fn drain(self) -> Box { self.block.state.drop().1 } } impl IsBlock for SealedBlock { @@ -332,15 +353,15 @@ impl IsBlock for SealedBlock { } /// Enact the block given by block header, transactions and uncles -pub fn enact<'x, 'y>(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: &'y LastHashes) -> Result, Error> { +pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, tracing: bool, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { { if ::log::max_log_level() >= ::log::LogLevel::Trace { - let s = State::from_existing(db.clone(), parent.state_root().clone(), engine.account_start_nonce()); + let s = State::from_existing(db.spawn(), parent.state_root().clone(), engine.account_start_nonce()); trace!("enact(): root={}, author={}, author_balance={}\n", s.root(), header.author(), s.balance(&header.author())); } } - let mut b = OpenBlock::new(engine, db, parent, last_hashes, header.author().clone(), header.extra_data().clone()); + let mut b = OpenBlock::new(engine, tracing, db, parent, last_hashes, header.author().clone(), x!(3141562), header.extra_data().clone()); b.set_difficulty(*header.difficulty()); b.set_gas_limit(*header.gas_limit()); b.set_timestamp(header.timestamp()); @@ -350,22 +371,22 @@ pub fn enact<'x, 'y>(header: &Header, transactions: &[SignedTransaction], uncles } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header -pub fn enact_bytes<'x, 'y>(block_bytes: &[u8], engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: &'y LastHashes) -> Result, Error> { +pub fn enact_bytes(block_bytes: &[u8], engine: &Engine, tracing: bool, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { let block = BlockView::new(block_bytes); let header = block.header(); - enact(&header, &block.transactions(), &block.uncles(), engine, db, parent, last_hashes) + enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes) } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header -pub fn enact_verified<'x, 'y>(block: &PreVerifiedBlock, engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: &'y LastHashes) -> Result, Error> { +pub fn enact_verified(block: &PreverifiedBlock, engine: &Engine, tracing: bool, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { let view = BlockView::new(&block.bytes); - enact(&block.header, &block.transactions, &view.uncles(), engine, db, parent, last_hashes) + enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes) } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards -pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, db: JournalDB, parent: &Header, last_hashes: &LastHashes) -> Result { +pub fn enact_and_seal(block_bytes: &[u8], engine: &Engine, tracing: bool, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { let header = BlockView::new(block_bytes).header_view(); - Ok(try!(try!(enact_bytes(block_bytes, engine, db, parent, last_hashes)).seal(header.seal()))) + Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes)).seal(engine, header.seal()))) } #[cfg(test)] @@ -382,11 +403,11 @@ mod tests { let genesis_header = engine.spec().genesis_header(); let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); - engine.spec().ensure_db_good(&mut db); + engine.spec().ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; - let b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]); + let b = OpenBlock::new(engine.deref(), false, db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]); let b = b.close(); - let _ = b.seal(vec![]); + let _ = b.seal(engine.deref(), vec![]); } #[test] @@ -397,15 +418,15 @@ mod tests { let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); - engine.spec().ensure_db_good(&mut db); - let b = OpenBlock::new(engine.deref(), db, &genesis_header, &vec![genesis_header.hash()], Address::zero(), vec![]).close().seal(vec![]).unwrap(); + engine.spec().ensure_db_good(db.as_hashdb_mut()); + let b = OpenBlock::new(engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), x!(3141562), vec![]).close().seal(engine.deref(), vec![]).unwrap(); let orig_bytes = b.rlp_bytes(); let orig_db = b.drain(); let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); - engine.spec().ensure_db_good(&mut db); - let e = enact_and_seal(&orig_bytes, engine.deref(), db, &genesis_header, &vec![genesis_header.hash()]).unwrap(); + engine.spec().ensure_db_good(db.as_hashdb_mut()); + let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()]).unwrap(); assert_eq!(e.rlp_bytes(), orig_bytes); @@ -413,4 +434,40 @@ mod tests { assert_eq!(orig_db.keys(), db.keys()); assert!(orig_db.keys().iter().filter(|k| orig_db.get(k.0) != db.get(k.0)).next() == None); } + + #[test] + fn enact_block_with_uncle() { + use spec::*; + let engine = Spec::new_test().to_engine().unwrap(); + let genesis_header = engine.spec().genesis_header(); + + let mut db_result = get_temp_journal_db(); + let mut db = db_result.take(); + engine.spec().ensure_db_good(db.as_hashdb_mut()); + let mut open_block = OpenBlock::new(engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), x!(3141562), vec![]); + let mut uncle1_header = Header::new(); + uncle1_header.extra_data = b"uncle1".to_vec(); + let mut uncle2_header = Header::new(); + uncle2_header.extra_data = b"uncle2".to_vec(); + 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(); + + let mut db_result = get_temp_journal_db(); + let mut db = db_result.take(); + engine.spec().ensure_db_good(db.as_hashdb_mut()); + let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()]).unwrap(); + + let bytes = e.rlp_bytes(); + assert_eq!(bytes, orig_bytes); + let uncles = BlockView::new(&bytes).uncles(); + assert_eq!(uncles[1].extra_data, b"uncle2"); + + let db = e.drain(); + assert_eq!(orig_db.keys(), db.keys()); + assert!(orig_db.keys().iter().filter(|k| orig_db.get(k.0) != db.get(k.0)).next() == None); + } } diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index 1a1dee48e..042df1dc1 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -28,6 +28,31 @@ use service::*; use client::BlockStatus; use util::panics::*; +known_heap_size!(0, UnverifiedBlock, VerifyingBlock, PreverifiedBlock); + +const MIN_MEM_LIMIT: usize = 16384; +const MIN_QUEUE_LIMIT: usize = 512; + +/// Block queue configuration +#[derive(Debug)] +pub struct BlockQueueConfig { + /// Maximum number of blocks to keep in unverified queue. + /// When the limit is reached, is_full returns true. + pub max_queue_size: usize, + /// Maximum heap memory to use. + /// When the limit is reached, is_full returns true. + pub max_mem_use: usize, +} + +impl Default for BlockQueueConfig { + fn default() -> Self { + BlockQueueConfig { + max_queue_size: 30000, + max_mem_use: 50 * 1024 * 1024, + } + } +} + /// Block queue status #[derive(Debug)] pub struct BlockQueueInfo { @@ -37,6 +62,12 @@ pub struct BlockQueueInfo { pub verified_queue_size: usize, /// Number of blocks being verified pub verifying_queue_size: usize, + /// Configured maximum number of blocks in the queue + pub max_queue_size: usize, + /// Configured maximum number of bytes to use + pub max_mem_use: usize, + /// Heap memory used in bytes + pub mem_used: usize, } impl BlockQueueInfo { @@ -48,7 +79,8 @@ impl BlockQueueInfo { /// Indicates that queue is full pub fn is_full(&self) -> bool { - self.unverified_queue_size + self.verified_queue_size + self.verifying_queue_size > MAX_UNVERIFIED_QUEUE_SIZE + self.unverified_queue_size + self.verified_queue_size + self.verifying_queue_size > self.max_queue_size || + self.mem_used > self.max_mem_use } /// Indicates that queue is empty @@ -63,22 +95,24 @@ pub struct BlockQueue { panic_handler: Arc, engine: Arc>, more_to_verify: Arc, - verification: Arc>, + verification: Arc, verifiers: Vec>, deleting: Arc, ready_signal: Arc, empty: Arc, - processing: RwLock> + processing: RwLock>, + max_queue_size: usize, + max_mem_use: usize, } -struct UnVerifiedBlock { +struct UnverifiedBlock { header: Header, bytes: Bytes, } struct VerifyingBlock { hash: H256, - block: Option, + block: Option, } struct QueueSignal { @@ -87,7 +121,7 @@ struct QueueSignal { } impl QueueSignal { - #[allow(bool_comparison)] + #[cfg_attr(feature="dev", allow(bool_comparison))] fn set(&self) { if self.signalled.compare_and_swap(false, true, AtomicOrdering::Relaxed) == false { self.message_channel.send(UserMessage(SyncMessage::BlockVerified)).expect("Error sending BlockVerified message"); @@ -98,20 +132,23 @@ impl QueueSignal { } } -#[derive(Default)] struct Verification { - unverified: VecDeque, - verified: VecDeque, - verifying: VecDeque, - bad: HashSet, + // All locks must be captured in the order declared here. + unverified: Mutex>, + verified: Mutex>, + verifying: Mutex>, + bad: Mutex>, } -const MAX_UNVERIFIED_QUEUE_SIZE: usize = 50000; - impl BlockQueue { /// Creates a new queue instance. - pub fn new(engine: Arc>, message_channel: IoChannel) -> BlockQueue { - let verification = Arc::new(Mutex::new(Verification::default())); + pub fn new(config: BlockQueueConfig, engine: Arc>, message_channel: IoChannel) -> BlockQueue { + let verification = Arc::new(Verification { + unverified: Mutex::new(VecDeque::new()), + verified: Mutex::new(VecDeque::new()), + verifying: Mutex::new(VecDeque::new()), + bad: Mutex::new(HashSet::new()), + }); let more_to_verify = Arc::new(Condvar::new()); let ready_signal = Arc::new(QueueSignal { signalled: AtomicBool::new(false), message_channel: message_channel }); let deleting = Arc::new(AtomicBool::new(false)); @@ -133,7 +170,7 @@ impl BlockQueue { .name(format!("Verifier #{}", i)) .spawn(move || { panic_handler.catch_panic(move || { - BlockQueue::verify(verification, engine, more_to_verify, ready_signal, deleting, empty) + BlockQueue::verify(verification, engine, more_to_verify, ready_signal, deleting, empty) }).unwrap() }) .expect("Error starting block verification thread") @@ -149,68 +186,73 @@ impl BlockQueue { deleting: deleting.clone(), processing: RwLock::new(HashSet::new()), empty: empty.clone(), + max_queue_size: max(config.max_queue_size, MIN_QUEUE_LIMIT), + max_mem_use: max(config.max_mem_use, MIN_MEM_LIMIT), } } - fn verify(verification: Arc>, engine: Arc>, wait: Arc, ready: Arc, deleting: Arc, empty: Arc) { - while !deleting.load(AtomicOrdering::Relaxed) { + fn verify(verification: Arc, engine: Arc>, wait: Arc, ready: Arc, deleting: Arc, empty: Arc) { + while !deleting.load(AtomicOrdering::Acquire) { { - let mut lock = verification.lock().unwrap(); + let mut unverified = verification.unverified.lock().unwrap(); - if lock.unverified.is_empty() && lock.verifying.is_empty() { + if unverified.is_empty() && verification.verifying.lock().unwrap().is_empty() { empty.notify_all(); } - while lock.unverified.is_empty() && !deleting.load(AtomicOrdering::Relaxed) { - lock = wait.wait(lock).unwrap(); + while unverified.is_empty() && !deleting.load(AtomicOrdering::Acquire) { + unverified = wait.wait(unverified).unwrap(); } - if deleting.load(AtomicOrdering::Relaxed) { + if deleting.load(AtomicOrdering::Acquire) { return; } } let block = { - let mut v = verification.lock().unwrap(); - if v.unverified.is_empty() { + let mut unverified = verification.unverified.lock().unwrap(); + if unverified.is_empty() { continue; } - let block = v.unverified.pop_front().unwrap(); - v.verifying.push_back(VerifyingBlock{ hash: block.header.hash(), block: None }); + let mut verifying = verification.verifying.lock().unwrap(); + let block = unverified.pop_front().unwrap(); + verifying.push_back(VerifyingBlock{ hash: block.header.hash(), block: None }); block }; let block_hash = block.header.hash(); match verify_block_unordered(block.header, block.bytes, engine.deref().deref()) { Ok(verified) => { - let mut v = verification.lock().unwrap(); - for e in &mut v.verifying { + let mut verifying = verification.verifying.lock().unwrap(); + for e in verifying.iter_mut() { if e.hash == block_hash { e.block = Some(verified); break; } } - if !v.verifying.is_empty() && v.verifying.front().unwrap().hash == block_hash { + if !verifying.is_empty() && verifying.front().unwrap().hash == block_hash { // we're next! - let mut vref = v.deref_mut(); - BlockQueue::drain_verifying(&mut vref.verifying, &mut vref.verified, &mut vref.bad); + let mut verified = verification.verified.lock().unwrap(); + let mut bad = verification.bad.lock().unwrap(); + BlockQueue::drain_verifying(&mut verifying, &mut verified, &mut bad); ready.set(); } }, Err(err) => { - let mut v = verification.lock().unwrap(); + let mut verifying = verification.verifying.lock().unwrap(); + let mut verified = verification.verified.lock().unwrap(); + let mut bad = verification.bad.lock().unwrap(); warn!(target: "client", "Stage 2 block verification failed for {}\nError: {:?}", block_hash, err); - v.bad.insert(block_hash.clone()); - v.verifying.retain(|e| e.hash != block_hash); - let mut vref = v.deref_mut(); - BlockQueue::drain_verifying(&mut vref.verifying, &mut vref.verified, &mut vref.bad); + bad.insert(block_hash.clone()); + verifying.retain(|e| e.hash != block_hash); + BlockQueue::drain_verifying(&mut verifying, &mut verified, &mut bad); ready.set(); } } } } - fn drain_verifying(verifying: &mut VecDeque, verified: &mut VecDeque, bad: &mut HashSet) { + fn drain_verifying(verifying: &mut VecDeque, verified: &mut VecDeque, bad: &mut HashSet) { while !verifying.is_empty() && verifying.front().unwrap().block.is_some() { let block = verifying.pop_front().unwrap().block.unwrap(); if bad.contains(&block.header.parent_hash) { @@ -223,19 +265,21 @@ impl BlockQueue { } /// Clear the queue and stop verification activity. - pub fn clear(&mut self) { - let mut verification = self.verification.lock().unwrap(); - verification.unverified.clear(); - verification.verifying.clear(); - verification.verified.clear(); + pub fn clear(&self) { + let mut unverified = self.verification.unverified.lock().unwrap(); + let mut verifying = self.verification.verifying.lock().unwrap(); + let mut verified = self.verification.verified.lock().unwrap(); + unverified.clear(); + verifying.clear(); + verified.clear(); self.processing.write().unwrap().clear(); } - /// Wait for queue to be empty - pub fn flush(&mut self) { - let mut verification = self.verification.lock().unwrap(); - while !verification.unverified.is_empty() || !verification.verifying.is_empty() { - verification = self.empty.wait(verification).unwrap(); + /// Wait for unverified queue to be empty + pub fn flush(&self) { + let mut unverified = self.verification.unverified.lock().unwrap(); + while !unverified.is_empty() || !self.verification.verifying.lock().unwrap().is_empty() { + unverified = self.empty.wait(unverified).unwrap(); } } @@ -244,84 +288,96 @@ impl BlockQueue { if self.processing.read().unwrap().contains(&hash) { return BlockStatus::Queued; } - if self.verification.lock().unwrap().bad.contains(&hash) { + if self.verification.bad.lock().unwrap().contains(&hash) { return BlockStatus::Bad; } BlockStatus::Unknown } /// Add a block to the queue. - pub fn import_block(&mut self, bytes: Bytes) -> ImportResult { + pub fn import_block(&self, bytes: Bytes) -> ImportResult { let header = BlockView::new(&bytes).header(); let h = header.hash(); - if self.processing.read().unwrap().contains(&h) { - return Err(ImportError::AlreadyQueued); - } { - let mut verification = self.verification.lock().unwrap(); - if verification.bad.contains(&h) { - return Err(ImportError::Bad(None)); + if self.processing.read().unwrap().contains(&h) { + return Err(x!(ImportError::AlreadyQueued)); } - if verification.bad.contains(&header.parent_hash) { - verification.bad.insert(h.clone()); - return Err(ImportError::Bad(None)); + let mut bad = self.verification.bad.lock().unwrap(); + if bad.contains(&h) { + return Err(x!(ImportError::KnownBad)); + } + + if bad.contains(&header.parent_hash) { + bad.insert(h.clone()); + return Err(x!(ImportError::KnownBad)); } } match verify_block_basic(&header, &bytes, self.engine.deref().deref()) { Ok(()) => { self.processing.write().unwrap().insert(h.clone()); - self.verification.lock().unwrap().unverified.push_back(UnVerifiedBlock { header: header, bytes: bytes }); + self.verification.unverified.lock().unwrap().push_back(UnverifiedBlock { header: header, bytes: bytes }); self.more_to_verify.notify_all(); Ok(h) }, Err(err) => { warn!(target: "client", "Stage 1 block verification failed for {}\nError: {:?}", BlockView::new(&bytes).header_view().sha3(), err); - self.verification.lock().unwrap().bad.insert(h.clone()); - Err(From::from(err)) + self.verification.bad.lock().unwrap().insert(h.clone()); + Err(err) } } } /// Mark given block and all its children as bad. Stops verification. - pub fn mark_as_bad(&mut self, hash: &H256) { - let mut verification_lock = self.verification.lock().unwrap(); - let mut verification = verification_lock.deref_mut(); - verification.bad.insert(hash.clone()); - self.processing.write().unwrap().remove(&hash); + pub fn mark_as_bad(&self, block_hashes: &[H256]) { + if block_hashes.is_empty() { + return; + } + let mut verified_lock = self.verification.verified.lock().unwrap(); + let mut verified = verified_lock.deref_mut(); + let mut bad = self.verification.bad.lock().unwrap(); + let mut processing = self.processing.write().unwrap(); + bad.reserve(block_hashes.len()); + for hash in block_hashes { + bad.insert(hash.clone()); + processing.remove(&hash); + } + let mut new_verified = VecDeque::new(); - for block in verification.verified.drain(..) { - if verification.bad.contains(&block.header.parent_hash) { - verification.bad.insert(block.header.hash()); - self.processing.write().unwrap().remove(&block.header.hash()); - } - else { + for block in verified.drain(..) { + if bad.contains(&block.header.parent_hash) { + bad.insert(block.header.hash()); + processing.remove(&block.header.hash()); + } else { new_verified.push_back(block); } } - verification.verified = new_verified; + *verified = new_verified; } /// Mark given block as processed - pub fn mark_as_good(&mut self, hashes: &[H256]) { + pub fn mark_as_good(&self, block_hashes: &[H256]) { + if block_hashes.is_empty() { + return; + } let mut processing = self.processing.write().unwrap(); - for h in hashes { - processing.remove(&h); + for hash in block_hashes { + processing.remove(&hash); } } /// Removes up to `max` verified blocks from the queue - pub fn drain(&mut self, max: usize) -> Vec { - let mut verification = self.verification.lock().unwrap(); - let count = min(max, verification.verified.len()); + pub fn drain(&self, max: usize) -> Vec { + let mut verified = self.verification.verified.lock().unwrap(); + let count = min(max, verified.len()); let mut result = Vec::with_capacity(count); for _ in 0..count { - let block = verification.verified.pop_front().unwrap(); + let block = verified.pop_front().unwrap(); result.push(block); } self.ready_signal.reset(); - if !verification.verified.is_empty() { + if !verified.is_empty() { self.ready_signal.set(); } result @@ -329,13 +385,42 @@ impl BlockQueue { /// Get queue status. pub fn queue_info(&self) -> BlockQueueInfo { - let verification = self.verification.lock().unwrap(); + let (unverified_len, unverified_bytes) = { + let v = self.verification.unverified.lock().unwrap(); + (v.len(), v.heap_size_of_children()) + }; + let (verifying_len, verifying_bytes) = { + let v = self.verification.verifying.lock().unwrap(); + (v.len(), v.heap_size_of_children()) + }; + let (verified_len, verified_bytes) = { + let v = self.verification.verified.lock().unwrap(); + (v.len(), v.heap_size_of_children()) + }; BlockQueueInfo { - verified_queue_size: verification.verified.len(), - unverified_queue_size: verification.unverified.len(), - verifying_queue_size: verification.verifying.len(), + unverified_queue_size: unverified_len, + verifying_queue_size: verifying_len, + verified_queue_size: verified_len, + max_queue_size: self.max_queue_size, + max_mem_use: self.max_mem_use, + mem_used: + unverified_bytes + + verifying_bytes + + verified_bytes + // TODO: https://github.com/servo/heapsize/pull/50 + //+ self.processing.read().unwrap().heap_size_of_children(), } } + + /// Optimise memory footprint of the heap fields. + pub fn collect_garbage(&self) { + { + self.verification.unverified.lock().unwrap().shrink_to_fit(); + self.verification.verifying.lock().unwrap().shrink_to_fit(); + self.verification.verified.lock().unwrap().shrink_to_fit(); + } + self.processing.write().unwrap().shrink_to_fit(); + } } impl MayPanic for BlockQueue { @@ -347,7 +432,7 @@ impl MayPanic for BlockQueue { impl Drop for BlockQueue { fn drop(&mut self) { self.clear(); - self.deleting.store(true, AtomicOrdering::Relaxed); + self.deleting.store(true, AtomicOrdering::Release); self.more_to_verify.notify_all(); for t in self.verifiers.drain(..) { t.join().unwrap(); @@ -367,7 +452,7 @@ mod tests { fn get_test_queue() -> BlockQueue { let spec = get_test_spec(); let engine = spec.to_engine().unwrap(); - BlockQueue::new(Arc::new(engine), IoChannel::disconnected()) + BlockQueue::new(BlockQueueConfig::default(), Arc::new(engine), IoChannel::disconnected()) } #[test] @@ -375,12 +460,12 @@ mod tests { // TODO better test let spec = Spec::new_test(); let engine = spec.to_engine().unwrap(); - let _ = BlockQueue::new(Arc::new(engine), IoChannel::disconnected()); + let _ = BlockQueue::new(BlockQueueConfig::default(), Arc::new(engine), IoChannel::disconnected()); } #[test] fn can_import_blocks() { - let mut queue = get_test_queue(); + let queue = get_test_queue(); if let Err(e) = queue.import_block(get_good_dummy_block()) { panic!("error importing block that is valid by definition({:?})", e); } @@ -388,7 +473,7 @@ mod tests { #[test] fn returns_error_for_duplicates() { - let mut queue = get_test_queue(); + let queue = get_test_queue(); if let Err(e) = queue.import_block(get_good_dummy_block()) { panic!("error importing block that is valid by definition({:?})", e); } @@ -397,7 +482,7 @@ mod tests { match duplicate_import { Err(e) => { match e { - ImportError::AlreadyQueued => {}, + Error::Import(ImportError::AlreadyQueued) => {}, _ => { panic!("must return AlreadyQueued error"); } } } @@ -407,7 +492,7 @@ mod tests { #[test] fn returns_ok_for_drained_duplicates() { - let mut queue = get_test_queue(); + let queue = get_test_queue(); let block = get_good_dummy_block(); let hash = BlockView::new(&block).header().hash().clone(); if let Err(e) = queue.import_block(block) { @@ -424,11 +509,26 @@ mod tests { #[test] fn returns_empty_once_finished() { - let mut queue = get_test_queue(); + let queue = get_test_queue(); queue.import_block(get_good_dummy_block()).expect("error importing block that is valid by definition"); queue.flush(); queue.drain(1); assert!(queue.queue_info().is_empty()); } + + #[test] + fn test_mem_limit() { + let spec = get_test_spec(); + let engine = spec.to_engine().unwrap(); + let mut config = BlockQueueConfig::default(); + config.max_mem_use = super::MIN_MEM_LIMIT; // empty queue uses about 15000 + let queue = BlockQueue::new(config, Arc::new(engine), IoChannel::disconnected()); + assert!(!queue.queue_info().is_full()); + let mut blocks = get_good_dummy_block_seq(50); + for b in blocks.drain(..) { + queue.import_block(b).unwrap(); + } + assert!(queue.queue_info().is_full()); + } } diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs deleted file mode 100644 index 9240ff800..000000000 --- a/ethcore/src/blockchain.rs +++ /dev/null @@ -1,865 +0,0 @@ -// 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 database. - -use util::*; -use rocksdb::{DB, WriteBatch, Writable}; -use header::*; -use extras::*; -use transaction::*; -use views::*; - -/// Represents a tree route between `from` block and `to` block: -pub struct TreeRoute { - /// A vector of hashes of all blocks, ordered from `from` to `to`. - pub blocks: Vec, - /// Best common ancestor of these blocks. - pub ancestor: H256, - /// An index where best common ancestor would be. - pub index: usize -} - -/// Represents blockchain's in-memory cache size in bytes. -#[derive(Debug)] -pub struct CacheSize { - /// Blocks cache size. - pub blocks: usize, - /// BlockDetails cache size. - pub block_details: usize, - /// Transaction addresses cache size. - pub transaction_addresses: usize, - /// Logs cache size. - pub block_logs: usize, - /// Blooms cache size. - pub blocks_blooms: usize -} - -impl CacheSize { - /// Total amount used by the cache. - fn total(&self) -> usize { self.blocks + self.block_details + self.transaction_addresses + self.block_logs + self.blocks_blooms } -} - -/// Information about best block gathered together -struct BestBlock { - pub hash: H256, - pub number: BlockNumber, - pub total_difficulty: U256 -} - -impl BestBlock { - fn new() -> BestBlock { - BestBlock { - hash: H256::new(), - number: 0, - total_difficulty: U256::from(0) - } - } -} - -/// Interface for querying blocks by hash and by number. -pub trait BlockProvider { - /// Returns true if the given block is known - /// (though not necessarily a part of the canon chain). - fn is_known(&self, hash: &H256) -> bool; - - /// Get raw block data - fn block(&self, hash: &H256) -> Option; - - /// Get the familial details concerning a block. - fn block_details(&self, hash: &H256) -> Option; - - /// Get the hash of given block's number. - fn block_hash(&self, index: BlockNumber) -> Option; - - /// Get the address of transaction with given hash. - fn transaction_address(&self, hash: &H256) -> Option; - - /// Get the partial-header of a block. - fn block_header(&self, hash: &H256) -> Option
{ - self.block(hash).map(|bytes| BlockView::new(&bytes).header()) - } - - /// Get a list of uncles for a given block. - /// Returns None if block deos not exist. - fn uncles(&self, hash: &H256) -> Option> { - self.block(hash).map(|bytes| BlockView::new(&bytes).uncles()) - } - - /// Get a list of uncle hashes for a given block. - /// Returns None if block does not exist. - fn uncle_hashes(&self, hash: &H256) -> Option> { - self.block(hash).map(|bytes| BlockView::new(&bytes).uncle_hashes()) - } - - /// Get the number of given block's hash. - fn block_number(&self, hash: &H256) -> Option { - self.block(hash).map(|bytes| BlockView::new(&bytes).header_view().number()) - } - - /// Get transaction with given transaction hash. - fn transaction(&self, address: &TransactionAddress) -> Option { - self.block(&address.block_hash).and_then(|bytes| BlockView::new(&bytes).localized_transaction_at(address.index)) - } - - /// Get a list of transactions for a given block. - /// Returns None if block does not exist. - fn transactions(&self, hash: &H256) -> Option> { - self.block(hash).map(|bytes| BlockView::new(&bytes).localized_transactions()) - } - - /// Returns reference to genesis hash. - fn genesis_hash(&self) -> H256 { - self.block_hash(0).expect("Genesis hash should always exist") - } - - /// Returns the header of the genesis block. - fn genesis_header(&self) -> Header { - self.block_header(&self.genesis_hash()).unwrap() - } -} - -#[derive(Debug, Hash, Eq, PartialEq, Clone)] -enum CacheID { - Block(H256), - Extras(ExtrasIndex, H256), -} - -struct CacheManager { - cache_usage: VecDeque>, - in_use: HashSet, -} - -/// Structure providing fast access to blockchain data. -/// -/// **Does not do input data verification.** -pub struct BlockChain { - pref_cache_size: usize, - max_cache_size: usize, - - best_block: RwLock, - - // block cache - blocks: RwLock>, - - // extra caches - block_details: RwLock>, - block_hashes: RwLock>, - transaction_addresses: RwLock>, - block_logs: RwLock>, - blocks_blooms: RwLock>, - - extras_db: DB, - blocks_db: DB, - - cache_man: RwLock, -} - -impl BlockProvider for BlockChain { - /// Returns true if the given block is known - /// (though not necessarily a part of the canon chain). - fn is_known(&self, hash: &H256) -> bool { - self.query_extras_exist(hash, &self.block_details) - } - - /// Get raw block data - fn block(&self, hash: &H256) -> Option { - { - let read = self.blocks.read().unwrap(); - if let Some(v) = read.get(hash) { - return Some(v.clone()); - } - } - - let opt = self.blocks_db.get(hash) - .expect("Low level database error. Some issue with disk?"); - - self.note_used(CacheID::Block(hash.clone())); - - match opt { - Some(b) => { - let bytes: Bytes = b.to_vec(); - let mut write = self.blocks.write().unwrap(); - write.insert(hash.clone(), bytes.clone()); - Some(bytes) - }, - None => None - } - } - - /// Get the familial details concerning a block. - fn block_details(&self, hash: &H256) -> Option { - self.query_extras(hash, &self.block_details) - } - - /// Get the hash of given block's number. - fn block_hash(&self, index: BlockNumber) -> Option { - self.query_extras(&index, &self.block_hashes) - } - - /// Get the address of transaction with given hash. - fn transaction_address(&self, hash: &H256) -> Option { - self.query_extras(hash, &self.transaction_addresses) - } -} - -const COLLECTION_QUEUE_SIZE: usize = 8; - -impl BlockChain { - /// Create new instance of blockchain from given Genesis - /// - /// ```rust - /// extern crate ethcore_util as util; - /// extern crate ethcore; - /// use std::env; - /// use std::str::FromStr; - /// use ethcore::spec::*; - /// use ethcore::blockchain::*; - /// use ethcore::ethereum; - /// use util::hash::*; - /// use util::uint::*; - /// - /// fn main() { - /// let spec = ethereum::new_frontier(); - /// - /// let mut dir = env::temp_dir(); - /// dir.push(H32::random().hex()); - /// - /// let bc = BlockChain::new(&spec.genesis_block(), &dir); - /// - /// let genesis_hash = "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"; - /// assert_eq!(bc.genesis_hash(), H256::from_str(genesis_hash).unwrap()); - /// assert!(bc.is_known(&bc.genesis_hash())); - /// assert_eq!(bc.genesis_hash(), bc.block_hash(0).unwrap()); - /// } - /// ``` - pub fn new(genesis: &[u8], path: &Path) -> BlockChain { - // open extras db - let mut extras_path = path.to_path_buf(); - extras_path.push("extras"); - let extras_db = DB::open_default(extras_path.to_str().unwrap()).unwrap(); - - // open blocks db - let mut blocks_path = path.to_path_buf(); - blocks_path.push("blocks"); - let blocks_db = DB::open_default(blocks_path.to_str().unwrap()).unwrap(); - - let mut cache_man = CacheManager{cache_usage: VecDeque::new(), in_use: HashSet::new()}; - (0..COLLECTION_QUEUE_SIZE).foreach(|_| cache_man.cache_usage.push_back(HashSet::new())); - - let bc = BlockChain { - pref_cache_size: 1 << 14, - max_cache_size: 1 << 20, - best_block: RwLock::new(BestBlock::new()), - blocks: RwLock::new(HashMap::new()), - block_details: RwLock::new(HashMap::new()), - block_hashes: RwLock::new(HashMap::new()), - transaction_addresses: RwLock::new(HashMap::new()), - block_logs: RwLock::new(HashMap::new()), - blocks_blooms: RwLock::new(HashMap::new()), - extras_db: extras_db, - blocks_db: blocks_db, - cache_man: RwLock::new(cache_man), - }; - - // load best block - let best_block_hash = match bc.extras_db.get(b"best").unwrap() { - Some(best) => H256::from_slice(&best), - None => { - // best block does not exist - // we need to insert genesis into the cache - let block = BlockView::new(genesis); - let header = block.header_view(); - let hash = block.sha3(); - - let details = BlockDetails { - number: header.number(), - total_difficulty: header.difficulty(), - parent: header.parent_hash(), - children: vec![] - }; - - bc.blocks_db.put(&hash, genesis).unwrap(); - - let batch = WriteBatch::new(); - batch.put_extras(&hash, &details); - batch.put_extras(&header.number(), &hash); - batch.put(b"best", &hash).unwrap(); - bc.extras_db.write(batch).unwrap(); - - hash - } - }; - - { - let mut best_block = bc.best_block.write().unwrap(); - best_block.number = bc.block_number(&best_block_hash).unwrap(); - best_block.total_difficulty = bc.block_details(&best_block_hash).unwrap().total_difficulty; - best_block.hash = best_block_hash; - } - - bc - } - - /// Set the cache configuration. - pub fn configure_cache(&mut self, pref_cache_size: usize, max_cache_size: usize) { - self.pref_cache_size = pref_cache_size; - self.max_cache_size = max_cache_size; - } - - /// Returns a tree route between `from` and `to`, which is a tuple of: - /// - /// - a vector of hashes of all blocks, ordered from `from` to `to`. - /// - /// - common ancestor of these blocks. - /// - /// - an index where best common ancestor would be - /// - /// 1.) from newer to older - /// - /// - bc: `A1 -> A2 -> A3 -> A4 -> A5` - /// - from: A5, to: A4 - /// - route: - /// - /// ```json - /// { blocks: [A5], ancestor: A4, index: 1 } - /// ``` - /// - /// 2.) from older to newer - /// - /// - bc: `A1 -> A2 -> A3 -> A4 -> A5` - /// - from: A3, to: A4 - /// - route: - /// - /// ```json - /// { blocks: [A4], ancestor: A3, index: 0 } - /// ``` - /// - /// 3.) fork: - /// - /// - bc: - /// - /// ```text - /// A1 -> A2 -> A3 -> A4 - /// -> B3 -> B4 - /// ``` - /// - from: B4, to: A4 - /// - route: - /// - /// ```json - /// { blocks: [B4, B3, A3, A4], ancestor: A2, index: 2 } - /// ``` - pub fn tree_route(&self, from: H256, to: H256) -> Option { - let from_details = match self.block_details(&from) { - Some(h) => h, - None => return None, - }; - let to_details = match self.block_details(&to) { - Some(h) => h, - None => return None, - }; - Some(self.tree_route_aux((&from_details, &from), (&to_details, &to))) - } - - /// Similar to `tree_route` function, but can be used to return a route - /// between blocks which may not be in database yet. - fn tree_route_aux(&self, from: (&BlockDetails, &H256), to: (&BlockDetails, &H256)) -> TreeRoute { - let mut from_branch = vec![]; - let mut to_branch = vec![]; - - let mut from_details = from.0.clone(); - let mut to_details = to.0.clone(); - let mut current_from = from.1.clone(); - let mut current_to = to.1.clone(); - - // reset from && to to the same level - while from_details.number > to_details.number { - from_branch.push(current_from); - current_from = from_details.parent.clone(); - from_details = self.block_details(&from_details.parent).unwrap(); - } - - while to_details.number > from_details.number { - to_branch.push(current_to); - current_to = to_details.parent.clone(); - to_details = self.block_details(&to_details.parent).unwrap(); - } - - assert_eq!(from_details.number, to_details.number); - - // move to shared parent - while current_from != current_to { - from_branch.push(current_from); - current_from = from_details.parent.clone(); - from_details = self.block_details(&from_details.parent).unwrap(); - - to_branch.push(current_to); - current_to = to_details.parent.clone(); - to_details = self.block_details(&to_details.parent).unwrap(); - } - - let index = from_branch.len(); - - from_branch.extend(to_branch.into_iter().rev()); - - TreeRoute { - blocks: from_branch, - ancestor: current_from, - index: index - } - } - - /// Inserts the block into backing cache database. - /// Expects the block to be valid and already verified. - /// If the block is already known, does nothing. - pub fn insert_block(&self, bytes: &[u8]) { - // create views onto rlp - let block = BlockView::new(bytes); - let header = block.header_view(); - let hash = header.sha3(); - - if self.is_known(&hash) { - return; - } - - // store block in db - self.blocks_db.put(&hash, &bytes).unwrap(); - let (batch, new_best, details) = self.block_to_extras_insert_batch(bytes); - - // update best block - let mut best_block = self.best_block.write().unwrap(); - if let Some(b) = new_best { - *best_block = b; - } - - // update caches - let mut write = self.block_details.write().unwrap(); - write.remove(&header.parent_hash()); - write.insert(hash.clone(), details); - self.note_used(CacheID::Block(hash)); - - // update extras database - self.extras_db.write(batch).unwrap(); - } - - /// Transforms block into WriteBatch that may be written into database - /// Additionally, if it's new best block it returns new best block object. - fn block_to_extras_insert_batch(&self, bytes: &[u8]) -> (WriteBatch, Option, BlockDetails) { - // create views onto rlp - let block = BlockView::new(bytes); - let header = block.header_view(); - - // prepare variables - let hash = block.sha3(); - let mut parent_details = self.block_details(&header.parent_hash()).expect("Invalid parent hash."); - let total_difficulty = parent_details.total_difficulty + header.difficulty(); - let is_new_best = total_difficulty > self.best_block_total_difficulty(); - let parent_hash = header.parent_hash(); - - // create current block details - let details = BlockDetails { - number: header.number(), - total_difficulty: total_difficulty, - parent: parent_hash.clone(), - children: vec![] - }; - - // prepare the batch - let batch = WriteBatch::new(); - - // insert new block details - batch.put_extras(&hash, &details); - - // update parent details - parent_details.children.push(hash.clone()); - batch.put_extras(&parent_hash, &parent_details); - - // update transaction addresses - for (i, tx_hash) in block.transaction_hashes().iter().enumerate() { - batch.put_extras(tx_hash, &TransactionAddress { - block_hash: hash.clone(), - index: i - }); - } - - // if it's not new best block, just return - if !is_new_best { - return (batch, None, details); - } - - // if its new best block we need to make sure that all ancestors - // are moved to "canon chain" - // find the route between old best block and the new one - let best_hash = self.best_block_hash(); - let best_details = self.block_details(&best_hash).expect("best block hash is invalid!"); - let route = self.tree_route_aux((&best_details, &best_hash), (&details, &hash)); - - match route.blocks.len() { - // its our parent - 1 => batch.put_extras(&header.number(), &hash), - // it is a fork - i if i > 1 => { - let ancestor_number = self.block_number(&route.ancestor).unwrap(); - let start_number = ancestor_number + 1; - for (index, hash) in route.blocks.iter().skip(route.index).enumerate() { - batch.put_extras(&(start_number + index as BlockNumber), hash); - } - }, - // route.blocks.len() could be 0 only if inserted block is best block, - // and this is not possible at this stage - _ => { unreachable!(); } - }; - - // this is new best block - batch.put(b"best", &hash).unwrap(); - - let best_block = BestBlock { - hash: hash, - number: header.number(), - total_difficulty: total_difficulty - }; - - (batch, Some(best_block), details) - } - - /// Returns true if transaction is known. - pub fn is_known_transaction(&self, hash: &H256) -> bool { - self.query_extras_exist(hash, &self.transaction_addresses) - } - - /// Get best block hash. - pub fn best_block_hash(&self) -> H256 { - self.best_block.read().unwrap().hash.clone() - } - - /// Get best block number. - pub fn best_block_number(&self) -> BlockNumber { - self.best_block.read().unwrap().number - } - - /// Get best block total difficulty. - pub fn best_block_total_difficulty(&self) -> U256 { - self.best_block.read().unwrap().total_difficulty - } - - /// Get the transactions' log blooms of a block. - pub fn log_blooms(&self, hash: &H256) -> Option { - self.query_extras(hash, &self.block_logs) - } - - fn query_extras(&self, hash: &K, cache: &RwLock>) -> Option where - T: Clone + Decodable + ExtrasIndexable, - K: ExtrasSliceConvertable + Eq + Hash + Clone { - { - let read = cache.read().unwrap(); - if let Some(v) = read.get(hash) { - return Some(v.clone()); - } - } - - if let Some(h) = hash.as_h256() { - self.note_used(CacheID::Extras(T::extras_index(), h.clone())); - } - - self.extras_db.get_extras(hash).map(| t: T | { - let mut write = cache.write().unwrap(); - write.insert(hash.clone(), t.clone()); - t - }) - } - - fn query_extras_exist(&self, hash: &K, cache: &RwLock>) -> bool where - K: ExtrasSliceConvertable + Eq + Hash + Clone, - T: ExtrasIndexable { - { - let read = cache.read().unwrap(); - if let Some(_) = read.get(hash) { - return true; - } - } - - self.extras_db.extras_exists::<_, T>(hash) - } - - /// Get current cache size. - pub fn cache_size(&self) -> CacheSize { - CacheSize { - blocks: self.blocks.read().unwrap().heap_size_of_children(), - block_details: self.block_details.read().unwrap().heap_size_of_children(), - transaction_addresses: self.transaction_addresses.read().unwrap().heap_size_of_children(), - block_logs: self.block_logs.read().unwrap().heap_size_of_children(), - blocks_blooms: self.blocks_blooms.read().unwrap().heap_size_of_children() - } - } - - /// Let the cache system know that a cacheable item has been used. - fn note_used(&self, id: CacheID) { - let mut cache_man = self.cache_man.write().unwrap(); - if !cache_man.cache_usage[0].contains(&id) { - cache_man.cache_usage[0].insert(id.clone()); - if cache_man.in_use.contains(&id) { - if let Some(c) = cache_man.cache_usage.iter_mut().skip(1).find(|e|e.contains(&id)) { - c.remove(&id); - } - } else { - cache_man.in_use.insert(id); - } - } - } - - /// Ticks our cache system and throws out any old data. - pub fn collect_garbage(&self) { - if self.cache_size().total() < self.pref_cache_size { return; } - - for _ in 0..COLLECTION_QUEUE_SIZE { - { - let mut cache_man = self.cache_man.write().unwrap(); - let mut blocks = self.blocks.write().unwrap(); - let mut block_details = self.block_details.write().unwrap(); - let mut block_hashes = self.block_hashes.write().unwrap(); - let mut transaction_addresses = self.transaction_addresses.write().unwrap(); - let mut block_logs = self.block_logs.write().unwrap(); - let mut blocks_blooms = self.blocks_blooms.write().unwrap(); - - for id in cache_man.cache_usage.pop_back().unwrap().into_iter() { - cache_man.in_use.remove(&id); - match id { - CacheID::Block(h) => { blocks.remove(&h); }, - CacheID::Extras(ExtrasIndex::BlockDetails, h) => { block_details.remove(&h); }, - CacheID::Extras(ExtrasIndex::TransactionAddress, h) => { transaction_addresses.remove(&h); }, - CacheID::Extras(ExtrasIndex::BlockLogBlooms, h) => { block_logs.remove(&h); }, - CacheID::Extras(ExtrasIndex::BlocksBlooms, h) => { blocks_blooms.remove(&h); }, - _ => panic!(), - } - } - cache_man.cache_usage.push_front(HashSet::new()); - - // TODO: handle block_hashes properly. - block_hashes.clear(); - } - if self.cache_size().total() < self.max_cache_size { break; } - } - - // TODO: m_lastCollection = chrono::system_clock::now(); - } -} - -#[cfg(test)] -mod tests { - use std::str::FromStr; - use rustc_serialize::hex::FromHex; - use util::hash::*; - use blockchain::*; - use tests::helpers::*; - - #[test] - fn valid_tests_extra32() { - let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0925002c3260b44e44c3edebad1cc442142b03020209df1ab8bb86752edbd2cd7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a0363659b251bf8b819179874c8cce7b9b983d7f3704cbb58a3b334431f7032871889032d09c281e1236c0c0".from_hex().unwrap(); - - let temp = RandomTempPath::new(); - let bc = BlockChain::new(&genesis, temp.as_path()); - - let genesis_hash = H256::from_str("3caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942").unwrap(); - - assert_eq!(bc.genesis_hash(), genesis_hash.clone()); - assert_eq!(bc.best_block_number(), 0); - assert_eq!(bc.best_block_hash(), genesis_hash.clone()); - assert_eq!(bc.block_hash(0), Some(genesis_hash.clone())); - assert_eq!(bc.block_hash(1), None); - - let first = "f90285f90219a03caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0d45893a296c1490a978e0bd321b5f2635d8280365c1fe9f693d65f233e791344a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fefd882560b845627cb99a00102030405060708091011121314151617181920212223242526272829303132a08ccb2837fb2923bd97e8f2d08ea32012d6e34be018c73e49a0f98843e8f47d5d88e53be49fec01012ef866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ba0cb088b8d2ff76a7b2c6616c9d02fb6b7a501afbf8b69d7180b09928a1b80b5e4a06448fe7476c606582039bb72a9f6f4b4fad18507b8dfbd00eebbe151cc573cd2c0".from_hex().unwrap(); - - bc.insert_block(&first); - - let first_hash = H256::from_str("a940e5af7d146b3b917c953a82e1966b906dace3a4e355b5b0a4560190357ea1").unwrap(); - - assert_eq!(bc.block_hash(0), Some(genesis_hash.clone())); - assert_eq!(bc.best_block_number(), 1); - assert_eq!(bc.best_block_hash(), first_hash.clone()); - assert_eq!(bc.block_hash(1), Some(first_hash.clone())); - assert_eq!(bc.block_details(&first_hash).unwrap().parent, genesis_hash.clone()); - assert_eq!(bc.block_details(&genesis_hash).unwrap().children, vec![first_hash.clone()]); - assert_eq!(bc.block_hash(2), None); - } - - #[test] - #[allow(cyclomatic_complexity)] - fn test_small_fork() { - let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a059262c330941f3fe2a34d16d6e3c7b30d2ceb37c6a0e9a994c494ee1a61d2410885aa4c8bf8e56e264c0c0".from_hex().unwrap(); - let b1 = "f90261f901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a0e78628dd45a1f8dc495594d83b76c588a3ee67463260f8b7d4a42f574aeab29aa0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd882520884562791e580a051b3ecba4e3f2b49c11d42dd0851ec514b1be3138080f72a2b6e83868275d98f8877671f479c414b47f862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca09e2709d7ec9bbe6b1bbbf0b2088828d14cd5e8642a1fee22dc74bfa89761a7f9a04bd8813dee4be989accdb708b1c2e325a7e9c695a8024e30e89d6c644e424747c0".from_hex().unwrap(); - let b2 = "f902ccf901f9a0437e51676ff10756fcfee5edd9159fa41dbcb1b2c592850450371cbecd54ee4fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); - let b3a = "f90261f901f9a036fde1253128666fcb95a5956da14a73489e988bb72738717ec1d31e1cee781aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a09dc4b1357c0b7b8108f8a098f4f9a1a274957bc9ebc22a9ae67ae81739e5b19ca007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefd882524d84562791eb80a074861666bd346c025889745c793b91ab9cd1e2ca19b5cf3c50d04d135b0a4d2b8809fe9587ea4cdc04f862f86002018304cb2f94ec0e71ad0a90ffe1909d27dac207f7680abba42d01801ba06fd84874d36d5de9e8e48978c03619b53a96b7ae0a4cd1ac118f103098b44801a00572596974dd7df4f9f69bd7456585618c568d8434ef6453391b89281ce12ae1c0".from_hex().unwrap(); - let b3b = "f90265f901f9a036fde1253128666fcb95a5956da14a73489e988bb72738717ec1d31e1cee781aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ab87dc338bfd6f662b1cd90bc0c9e40a1b2146a095312393c9e13ce3a5008b09a0e609b7a7d4b8a2403ec1268627ecd98783627246e8f1b26addb3ff504f76a054a0592fabf92476512952db3a69a2481a42912e668a1ee28c4c322e703bb665f8beb90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefd882a1f084562791ee80a0fe7098fa7e4ac5d637eea81fb23f8f78346826dbab430068dd9a249d0afa99818853e1a6b201ae3545f866f86402018304cb2f94ec0e71ad0a90ffe1909d27dac207f7680abba42d0284c04062261ca06edc9ce8e7da4cc34067beb325dcad59e5655a164a5100a50bc3eb681b12c716a0abf9053d5de65b1be81fe50d327b84de685efbeecea34e7b747180a6c6023e44c0".from_hex().unwrap(); - - let genesis_hash = H256::from_str("5716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2").unwrap(); - let b1_hash = H256::from_str("437e51676ff10756fcfee5edd9159fa41dbcb1b2c592850450371cbecd54ee4f").unwrap(); - let b2_hash = H256::from_str("36fde1253128666fcb95a5956da14a73489e988bb72738717ec1d31e1cee781a").unwrap(); - let b3a_hash = H256::from_str("c208f88c9f5bf7e00840439742c12e5226d9752981f3ec0521bdcb6dd08af277").unwrap(); - let b3b_hash = H256::from_str("bf72270ae0d95c9ea39a6adab994793fddb8c10fba7391e26279474124605d54").unwrap(); - - // b3a is a part of canon chain, whereas b3b is part of sidechain - let best_block_hash = H256::from_str("c208f88c9f5bf7e00840439742c12e5226d9752981f3ec0521bdcb6dd08af277").unwrap(); - - let temp = RandomTempPath::new(); - let bc = BlockChain::new(&genesis, temp.as_path()); - bc.insert_block(&b1); - bc.insert_block(&b2); - bc.insert_block(&b3a); - bc.insert_block(&b3b); - - assert_eq!(bc.best_block_hash(), best_block_hash); - assert_eq!(bc.block_number(&genesis_hash).unwrap(), 0); - assert_eq!(bc.block_number(&b1_hash).unwrap(), 1); - assert_eq!(bc.block_number(&b2_hash).unwrap(), 2); - assert_eq!(bc.block_number(&b3a_hash).unwrap(), 3); - assert_eq!(bc.block_number(&b3b_hash).unwrap(), 3); - - assert_eq!(bc.block_hash(0).unwrap(), genesis_hash); - assert_eq!(bc.block_hash(1).unwrap(), b1_hash); - assert_eq!(bc.block_hash(2).unwrap(), b2_hash); - assert_eq!(bc.block_hash(3).unwrap(), b3a_hash); - - // test trie route - let r0_1 = bc.tree_route(genesis_hash.clone(), b1_hash.clone()).unwrap(); - assert_eq!(r0_1.ancestor, genesis_hash); - assert_eq!(r0_1.blocks, [b1_hash.clone()]); - assert_eq!(r0_1.index, 0); - - let r0_2 = bc.tree_route(genesis_hash.clone(), b2_hash.clone()).unwrap(); - assert_eq!(r0_2.ancestor, genesis_hash); - assert_eq!(r0_2.blocks, [b1_hash.clone(), b2_hash.clone()]); - assert_eq!(r0_2.index, 0); - - let r1_3a = bc.tree_route(b1_hash.clone(), b3a_hash.clone()).unwrap(); - assert_eq!(r1_3a.ancestor, b1_hash); - assert_eq!(r1_3a.blocks, [b2_hash.clone(), b3a_hash.clone()]); - assert_eq!(r1_3a.index, 0); - - let r1_3b = bc.tree_route(b1_hash.clone(), b3b_hash.clone()).unwrap(); - assert_eq!(r1_3b.ancestor, b1_hash); - assert_eq!(r1_3b.blocks, [b2_hash.clone(), b3b_hash.clone()]); - assert_eq!(r1_3b.index, 0); - - let r3a_3b = bc.tree_route(b3a_hash.clone(), b3b_hash.clone()).unwrap(); - assert_eq!(r3a_3b.ancestor, b2_hash); - assert_eq!(r3a_3b.blocks, [b3a_hash.clone(), b3b_hash.clone()]); - assert_eq!(r3a_3b.index, 1); - - let r1_0 = bc.tree_route(b1_hash.clone(), genesis_hash.clone()).unwrap(); - assert_eq!(r1_0.ancestor, genesis_hash); - assert_eq!(r1_0.blocks, [b1_hash.clone()]); - assert_eq!(r1_0.index, 1); - - let r2_0 = bc.tree_route(b2_hash.clone(), genesis_hash.clone()).unwrap(); - assert_eq!(r2_0.ancestor, genesis_hash); - assert_eq!(r2_0.blocks, [b2_hash.clone(), b1_hash.clone()]); - assert_eq!(r2_0.index, 2); - - let r3a_1 = bc.tree_route(b3a_hash.clone(), b1_hash.clone()).unwrap(); - assert_eq!(r3a_1.ancestor, b1_hash); - assert_eq!(r3a_1.blocks, [b3a_hash.clone(), b2_hash.clone()]); - assert_eq!(r3a_1.index, 2); - - let r3b_1 = bc.tree_route(b3b_hash.clone(), b1_hash.clone()).unwrap(); - assert_eq!(r3b_1.ancestor, b1_hash); - assert_eq!(r3b_1.blocks, [b3b_hash.clone(), b2_hash.clone()]); - assert_eq!(r3b_1.index, 2); - - let r3b_3a = bc.tree_route(b3b_hash.clone(), b3a_hash.clone()).unwrap(); - assert_eq!(r3b_3a.ancestor, b2_hash); - assert_eq!(r3b_3a.blocks, [b3b_hash.clone(), b3a_hash.clone()]); - assert_eq!(r3b_3a.index, 1); - } - - #[test] - fn test_reopen_blockchain_db() { - let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a059262c330941f3fe2a34d16d6e3c7b30d2ceb37c6a0e9a994c494ee1a61d2410885aa4c8bf8e56e264c0c0".from_hex().unwrap(); - let b1 = "f90261f901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a0e78628dd45a1f8dc495594d83b76c588a3ee67463260f8b7d4a42f574aeab29aa0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd882520884562791e580a051b3ecba4e3f2b49c11d42dd0851ec514b1be3138080f72a2b6e83868275d98f8877671f479c414b47f862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca09e2709d7ec9bbe6b1bbbf0b2088828d14cd5e8642a1fee22dc74bfa89761a7f9a04bd8813dee4be989accdb708b1c2e325a7e9c695a8024e30e89d6c644e424747c0".from_hex().unwrap(); - let genesis_hash = H256::from_str("5716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2").unwrap(); - let b1_hash = H256::from_str("437e51676ff10756fcfee5edd9159fa41dbcb1b2c592850450371cbecd54ee4f").unwrap(); - - let temp = RandomTempPath::new(); - { - let bc = BlockChain::new(&genesis, temp.as_path()); - assert_eq!(bc.best_block_hash(), genesis_hash); - bc.insert_block(&b1); - assert_eq!(bc.best_block_hash(), b1_hash); - } - - { - let bc = BlockChain::new(&genesis, temp.as_path()); - assert_eq!(bc.best_block_hash(), b1_hash); - } - } - - #[test] - fn can_contain_arbitrary_block_sequence() { - let bc_result = generate_dummy_blockchain(50); - let bc = bc_result.reference(); - assert_eq!(bc.best_block_number(), 49); - } - - #[test] - fn can_collect_garbage() { - let bc_result = generate_dummy_blockchain(3000); - let bc = bc_result.reference(); - - assert_eq!(bc.best_block_number(), 2999); - let best_hash = bc.best_block_hash(); - let mut block_header = bc.block_header(&best_hash); - - while !block_header.is_none() { - block_header = bc.block_header(&block_header.unwrap().parent_hash); - } - assert!(bc.cache_size().blocks > 1024 * 1024); - - for _ in 0..2 { - bc.collect_garbage(); - } - assert!(bc.cache_size().blocks < 1024 * 1024); - } - - #[test] - fn can_contain_arbitrary_block_sequence_with_extra() { - let bc_result = generate_dummy_blockchain_with_extra(25); - let bc = bc_result.reference(); - assert_eq!(bc.best_block_number(), 24); - } - - #[test] - fn can_contain_only_genesis_block() { - let bc_result = generate_dummy_empty_blockchain(); - let bc = bc_result.reference(); - assert_eq!(bc.best_block_number(), 0); - } - - #[test] - fn find_transaction_by_hash() { - let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0af81e09f8c46ca322193edfda764fa7e88e81923f802f1d325ec0b0308ac2cd0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200008083023e38808454c98c8142a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421880102030405060708c0c0".from_hex().unwrap(); - let b1 = "f904a8f901faa0ce1f26f798dd03c8782d63b3e42e79a64eaea5694ea686ac5d7ce3df5171d1aea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0a65c2364cd0f1542d761823dc0109c6b072f14c20459598c5455c274601438f4a070616ebd7ad2ed6fb7860cf7e9df00163842351c38a87cac2c1cb193895035a2a05c5b4fc43c2d45787f54e1ae7d27afdb4ad16dfc567c5692070d5c4556e0b1d7b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200000183023ec683021536845685109780a029f07836e4e59229b3a065913afc27702642c683bba689910b2b2fd45db310d3888957e6d004a31802f902a7f85f800a8255f094aaaf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca0575da4e21b66fa764be5f74da9389e67693d066fb0d1312e19e17e501da00ecda06baf5a5327595f6619dfc2fcb3f2e6fb410b5810af3cb52d0e7508038e91a188f85f010a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba04fa966bf34b93abc1bcd665554b7f316b50f928477b50be0f3285ead29d18c5ba017bba0eeec1625ab433746955e125d46d80b7fdc97386c51266f842d8e02192ef85f020a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca004377418ae981cc32b1312b4a427a1d69a821b28db8584f5f2bd8c6d42458adaa053a1dba1af177fac92f3b6af0a9fa46a22adf56e686c93794b6a012bf254abf5f85f030a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca04fe13febd28a05f4fcb2f451d7ddc2dda56486d9f8c79a62b0ba4da775122615a0651b2382dd402df9ebc27f8cb4b2e0f3cea68dda2dca0ee9603608f0b6f51668f85f040a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba078e6a0ba086a08f8450e208a399bb2f2d2a0d984acd2517c7c7df66ccfab567da013254002cd45a97fac049ae00afbc43ed0d9961d0c56a3b2382c80ce41c198ddf85f050a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba0a7174d8f43ea71c8e3ca9477691add8d80ac8e0ed89d8d8b572041eef81f4a54a0534ea2e28ec4da3b5b944b18c51ec84a5cf35f5b3343c5fb86521fd2d388f506f85f060a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba034bd04065833536a10c77ee2a43a5371bc6d34837088b861dd9d4b7f44074b59a078807715786a13876d3455716a6b9cb2186b7a4887a5c31160fc877454958616c0".from_hex().unwrap(); - let b1_hash = H256::from_str("f53f268d23a71e85c7d6d83a9504298712b84c1a2ba220441c86eeda0bf0b6e3").unwrap(); - - let temp = RandomTempPath::new(); - let bc = BlockChain::new(&genesis, temp.as_path()); - bc.insert_block(&b1); - - let transactions = bc.transactions(&b1_hash).unwrap(); - assert_eq!(transactions.len(), 7); - for t in transactions { - assert_eq!(bc.transaction(&bc.transaction_address(&t.hash()).unwrap()).unwrap(), t); - } - } -} diff --git a/ethcore/src/blockchain/best_block.rs b/ethcore/src/blockchain/best_block.rs new file mode 100644 index 000000000..00c092713 --- /dev/null +++ b/ethcore/src/blockchain/best_block.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 . + +use util::numbers::{U256,H256}; +use header::BlockNumber; + +/// Best block info. +#[derive(Default)] +pub struct BestBlock { + /// Best block hash. + pub hash: H256, + /// Best block number. + pub number: BlockNumber, + /// Best block total difficulty. + pub total_difficulty: U256 +} diff --git a/ethcore/src/blockchain/block_info.rs b/ethcore/src/blockchain/block_info.rs new file mode 100644 index 000000000..cf16a8834 --- /dev/null +++ b/ethcore/src/blockchain/block_info.rs @@ -0,0 +1,51 @@ +// 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,H256}; +use header::BlockNumber; + +/// Brief info about inserted block. +#[derive(Clone)] +pub struct BlockInfo { + /// Block hash. + pub hash: H256, + /// Block number. + pub number: BlockNumber, + /// Total block difficulty. + pub total_difficulty: U256, + /// Block location in blockchain. + pub location: BlockLocation +} + +/// Describes location of newly inserted block. +#[derive(Clone)] +pub enum BlockLocation { + /// It's part of the canon chain. + CanonChain, + /// It's not a part of the canon chain. + Branch, + /// It's part of the fork which should become canon chain, + /// because it's total difficulty is higher than current + /// canon chain difficulty. + BranchBecomingCanonChain { + /// Hash of the newest common ancestor with old canon chain. + ancestor: H256, + /// Hashes of the blocks between ancestor and this block. + enacted: Vec, + /// Hashes of the blocks which were invalidated. + retracted: Vec, + } +} diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs new file mode 100644 index 000000000..43920708b --- /dev/null +++ b/ethcore/src/blockchain/blockchain.rs @@ -0,0 +1,1217 @@ +// 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 database. + +use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrder}; +use util::*; +use header::*; +use extras::*; +use transaction::*; +use views::*; +use receipt::Receipt; +use chainfilter::{ChainFilter, BloomIndex, FilterDataSource}; +use blockchain::block_info::{BlockInfo, BlockLocation}; +use blockchain::best_block::BestBlock; +use blockchain::bloom_indexer::BloomIndexer; +use blockchain::tree_route::TreeRoute; +use blockchain::update::ExtrasUpdate; +use blockchain::{CacheSize, ImportRoute}; + +const BLOOM_INDEX_SIZE: usize = 16; +const BLOOM_LEVELS: u8 = 3; + +/// Blockchain configuration. +#[derive(Debug)] +pub struct BlockChainConfig { + /// Preferred cache size in bytes. + pub pref_cache_size: usize, + /// Maximum cache size in bytes. + pub max_cache_size: usize, +} + +impl Default for BlockChainConfig { + fn default() -> Self { + BlockChainConfig { + pref_cache_size: 1 << 14, + max_cache_size: 1 << 20, + } + } +} + +/// Interface for querying blocks by hash and by number. +pub trait BlockProvider { + /// True if we store full tracing information for transactions. + fn have_tracing(&self) -> bool; + + /// Returns true if the given block is known + /// (though not necessarily a part of the canon chain). + fn is_known(&self, hash: &H256) -> bool; + + /// Get raw block data + fn block(&self, hash: &H256) -> Option; + + /// Get the familial details concerning a block. + fn block_details(&self, hash: &H256) -> Option; + + /// Get the hash of given block's number. + fn block_hash(&self, index: BlockNumber) -> Option; + + /// Get the address of transaction with given hash. + fn transaction_address(&self, hash: &H256) -> Option; + + /// Get receipts of block with given hash. + fn block_receipts(&self, hash: &H256) -> Option; + + /// Get the partial-header of a block. + fn block_header(&self, hash: &H256) -> Option
{ + self.block(hash).map(|bytes| BlockView::new(&bytes).header()) + } + + /// Get a list of uncles for a given block. + /// Returns None if block does not exist. + fn uncles(&self, hash: &H256) -> Option> { + self.block(hash).map(|bytes| BlockView::new(&bytes).uncles()) + } + + /// Get a list of uncle hashes for a given block. + /// Returns None if block does not exist. + fn uncle_hashes(&self, hash: &H256) -> Option> { + self.block(hash).map(|bytes| BlockView::new(&bytes).uncle_hashes()) + } + + /// Get the number of given block's hash. + fn block_number(&self, hash: &H256) -> Option { + self.block(hash).map(|bytes| BlockView::new(&bytes).header_view().number()) + } + + /// Get transaction with given transaction hash. + fn transaction(&self, address: &TransactionAddress) -> Option { + 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> { + self.block(hash).map(|bytes| BlockView::new(&bytes).localized_transactions()) + } + + /// Returns reference to genesis hash. + fn genesis_hash(&self) -> H256 { + self.block_hash(0).expect("Genesis hash should always exist") + } + + /// Returns the header of the genesis block. + fn genesis_header(&self) -> Header { + self.block_header(&self.genesis_hash()).unwrap() + } + + /// Returns numbers of blocks containing given bloom. + fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockNumber, to_block: BlockNumber) -> Vec; +} + +#[derive(Debug, Hash, Eq, PartialEq, Clone)] +enum CacheID { + Block(H256), + Extras(ExtrasIndex, H256), +} + +struct CacheManager { + cache_usage: VecDeque>, + in_use: HashSet, +} + +/// Structure providing fast access to blockchain data. +/// +/// **Does not do input data verification.** +pub struct BlockChain { + // All locks must be captured in the order declared here. + pref_cache_size: AtomicUsize, + max_cache_size: AtomicUsize, + + best_block: RwLock, + + // block cache + blocks: RwLock>, + + // extra caches + block_details: RwLock>, + block_hashes: RwLock>, + transaction_addresses: RwLock>, + block_logs: RwLock>, + blocks_blooms: RwLock>, + block_receipts: RwLock>, + + extras_db: Database, + blocks_db: Database, + + cache_man: RwLock, + + // blooms indexing + bloom_indexer: BloomIndexer, + + insert_lock: Mutex<()> +} + +impl FilterDataSource for BlockChain { + fn bloom_at_index(&self, bloom_index: &BloomIndex) -> Option { + let location = self.bloom_indexer.location(bloom_index); + self.blocks_blooms(&location.hash).and_then(|blooms| blooms.blooms.into_iter().nth(location.index).cloned()) + } +} + +impl BlockProvider for BlockChain { + /// Returns true if the given block is known + /// (though not necessarily a part of the canon chain). + fn is_known(&self, hash: &H256) -> bool { + self.query_extras_exist(hash, &self.block_details) + } + + // We do not store tracing information. + fn have_tracing(&self) -> bool { false } + + /// Get raw block data + fn block(&self, hash: &H256) -> Option { + { + let read = self.blocks.read().unwrap(); + if let Some(v) = read.get(hash) { + return Some(v.clone()); + } + } + + let opt = self.blocks_db.get(hash) + .expect("Low level database error. Some issue with disk?"); + + self.note_used(CacheID::Block(hash.clone())); + + match opt { + Some(b) => { + let bytes: Bytes = b.to_vec(); + let mut write = self.blocks.write().unwrap(); + write.insert(hash.clone(), bytes.clone()); + Some(bytes) + }, + None => None + } + } + + /// Get the familial details concerning a block. + fn block_details(&self, hash: &H256) -> Option { + self.query_extras(hash, &self.block_details) + } + + /// Get the hash of given block's number. + fn block_hash(&self, index: BlockNumber) -> Option { + self.query_extras(&index, &self.block_hashes) + } + + /// Get the address of transaction with given hash. + fn transaction_address(&self, hash: &H256) -> Option { + self.query_extras(hash, &self.transaction_addresses) + } + + /// Get receipts of block with given hash. + fn block_receipts(&self, hash: &H256) -> Option { + self.query_extras(hash, &self.block_receipts) + } + + /// Returns numbers of blocks containing given bloom. + fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockNumber, to_block: BlockNumber) -> Vec { + let filter = ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels()); + filter.blocks_with_bloom(bloom, from_block as usize, to_block as usize).into_iter().map(|b| b as BlockNumber).collect() + } +} + +const COLLECTION_QUEUE_SIZE: usize = 8; + +pub struct AncestryIter<'a> { + current: H256, + chain: &'a BlockChain, +} + +impl<'a> Iterator for AncestryIter<'a> { + type Item = H256; + fn next(&mut self) -> Option { + if self.current.is_zero() { + Option::None + } else { + let mut n = self.chain.block_details(&self.current).unwrap().parent; + mem::swap(&mut self.current, &mut n); + Some(n) + } + } +} + +impl BlockChain { + /// Create new instance of blockchain from given Genesis + pub fn new(config: BlockChainConfig, genesis: &[u8], path: &Path) -> BlockChain { + // open extras db + let mut extras_path = path.to_path_buf(); + extras_path.push("extras"); + let extras_db = Database::open_default(extras_path.to_str().unwrap()).unwrap(); + + // open blocks db + let mut blocks_path = path.to_path_buf(); + blocks_path.push("blocks"); + let blocks_db = Database::open_default(blocks_path.to_str().unwrap()).unwrap(); + + let mut cache_man = CacheManager{cache_usage: VecDeque::new(), in_use: HashSet::new()}; + (0..COLLECTION_QUEUE_SIZE).foreach(|_| cache_man.cache_usage.push_back(HashSet::new())); + + let bc = BlockChain { + pref_cache_size: AtomicUsize::new(config.pref_cache_size), + max_cache_size: AtomicUsize::new(config.max_cache_size), + best_block: RwLock::new(BestBlock::default()), + blocks: RwLock::new(HashMap::new()), + block_details: RwLock::new(HashMap::new()), + block_hashes: RwLock::new(HashMap::new()), + transaction_addresses: RwLock::new(HashMap::new()), + block_logs: RwLock::new(HashMap::new()), + blocks_blooms: RwLock::new(HashMap::new()), + block_receipts: RwLock::new(HashMap::new()), + extras_db: extras_db, + blocks_db: blocks_db, + cache_man: RwLock::new(cache_man), + bloom_indexer: BloomIndexer::new(BLOOM_INDEX_SIZE, BLOOM_LEVELS), + insert_lock: Mutex::new(()), + }; + + // load best block + let best_block_hash = match bc.extras_db.get(b"best").unwrap() { + Some(best) => H256::from_slice(&best), + None => { + // best block does not exist + // we need to insert genesis into the cache + let block = BlockView::new(genesis); + let header = block.header_view(); + let hash = block.sha3(); + + let details = BlockDetails { + number: header.number(), + total_difficulty: header.difficulty(), + parent: header.parent_hash(), + children: vec![] + }; + + bc.blocks_db.put(&hash, genesis).unwrap(); + + let batch = DBTransaction::new(); + batch.put_extras(&hash, &details); + batch.put_extras(&header.number(), &hash); + batch.put(b"best", &hash).unwrap(); + bc.extras_db.write(batch).unwrap(); + + hash + } + }; + + { + let mut best_block = bc.best_block.write().unwrap(); + best_block.number = bc.block_number(&best_block_hash).unwrap(); + best_block.total_difficulty = bc.block_details(&best_block_hash).unwrap().total_difficulty; + best_block.hash = best_block_hash; + } + + bc + } + + /// Set the cache configuration. + pub fn configure_cache(&self, pref_cache_size: usize, max_cache_size: usize) { + self.pref_cache_size.store(pref_cache_size, AtomicOrder::Relaxed); + self.max_cache_size.store(max_cache_size, AtomicOrder::Relaxed); + } + + /// Returns a tree route between `from` and `to`, which is a tuple of: + /// + /// - a vector of hashes of all blocks, ordered from `from` to `to`. + /// + /// - common ancestor of these blocks. + /// + /// - an index where best common ancestor would be + /// + /// 1.) from newer to older + /// + /// - bc: `A1 -> A2 -> A3 -> A4 -> A5` + /// - from: A5, to: A4 + /// - route: + /// + /// ```json + /// { blocks: [A5], ancestor: A4, index: 1 } + /// ``` + /// + /// 2.) from older to newer + /// + /// - bc: `A1 -> A2 -> A3 -> A4 -> A5` + /// - from: A3, to: A4 + /// - route: + /// + /// ```json + /// { blocks: [A4], ancestor: A3, index: 0 } + /// ``` + /// + /// 3.) fork: + /// + /// - bc: + /// + /// ```text + /// A1 -> A2 -> A3 -> A4 + /// -> B3 -> B4 + /// ``` + /// - from: B4, to: A4 + /// - route: + /// + /// ```json + /// { blocks: [B4, B3, A3, A4], ancestor: A2, index: 2 } + /// ``` + pub fn tree_route(&self, from: H256, to: H256) -> TreeRoute { + let mut from_branch = vec![]; + let mut to_branch = vec![]; + + let mut from_details = self.block_details(&from).expect(&format!("0. Expected to find details for block {:?}", from)); + let mut to_details = self.block_details(&to).expect(&format!("1. Expected to find details for block {:?}", to)); + let mut current_from = from; + let mut current_to = to; + + // reset from && to to the same level + while from_details.number > to_details.number { + from_branch.push(current_from); + current_from = from_details.parent.clone(); + from_details = self.block_details(&from_details.parent).expect(&format!("2. Expected to find details for block {:?}", from_details.parent)); + } + + while to_details.number > from_details.number { + to_branch.push(current_to); + current_to = to_details.parent.clone(); + to_details = self.block_details(&to_details.parent).expect(&format!("3. Expected to find details for block {:?}", to_details.parent)); + } + + assert_eq!(from_details.number, to_details.number); + + // move to shared parent + while current_from != current_to { + from_branch.push(current_from); + current_from = from_details.parent.clone(); + from_details = self.block_details(&from_details.parent).expect(&format!("4. Expected to find details for block {:?}", from_details.parent)); + + to_branch.push(current_to); + current_to = to_details.parent.clone(); + to_details = self.block_details(&to_details.parent).expect(&format!("5. Expected to find details for block {:?}", from_details.parent)); + } + + let index = from_branch.len(); + + from_branch.extend(to_branch.into_iter().rev()); + + TreeRoute { + blocks: from_branch, + ancestor: current_from, + index: index + } + } + + /// Inserts the block into backing cache database. + /// Expects the block to be valid and already verified. + /// If the block is already known, does nothing. + pub fn insert_block(&self, bytes: &[u8], receipts: Vec) -> ImportRoute { + // create views onto rlp + let block = BlockView::new(bytes); + let header = block.header_view(); + let hash = header.sha3(); + + if self.is_known(&hash) { + return ImportRoute::none(); + } + + let _lock = self.insert_lock.lock(); + // store block in db + self.blocks_db.put(&hash, &bytes).unwrap(); + + let info = self.block_info(bytes); + + self.apply_update(ExtrasUpdate { + block_hashes: self.prepare_block_hashes_update(bytes, &info), + block_details: self.prepare_block_details_update(bytes, &info), + block_receipts: self.prepare_block_receipts_update(receipts, &info), + transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info), + blocks_blooms: self.prepare_block_blooms_update(bytes, &info), + info: info.clone(), + }); + + ImportRoute::from(info) + } + + /// Applies extras update. + fn apply_update(&self, update: ExtrasUpdate) { + let batch = DBTransaction::new(); + batch.put(b"best", &update.info.hash).unwrap(); + + { + let mut write_details = self.block_details.write().unwrap(); + for (hash, details) in update.block_details.into_iter() { + batch.put_extras(&hash, &details); + self.note_used(CacheID::Extras(ExtrasIndex::BlockDetails, hash.clone())); + write_details.insert(hash, details); + } + } + + { + let mut write_receipts = self.block_receipts.write().unwrap(); + for (hash, receipt) in &update.block_receipts { + batch.put_extras(hash, receipt); + write_receipts.remove(hash); + } + } + + { + let mut write_blocks_blooms = self.blocks_blooms.write().unwrap(); + for (bloom_hash, blocks_bloom) in &update.blocks_blooms { + batch.put_extras(bloom_hash, blocks_bloom); + write_blocks_blooms.remove(bloom_hash); + } + } + + // These cached values must be updated last and togeterh + { + let mut best_block = self.best_block.write().unwrap(); + let mut write_hashes = self.block_hashes.write().unwrap(); + let mut write_txs = self.transaction_addresses.write().unwrap(); + + // update best block + match update.info.location { + BlockLocation::Branch => (), + _ => { + *best_block = BestBlock { + hash: update.info.hash, + number: update.info.number, + total_difficulty: update.info.total_difficulty + }; + } + } + + for (number, hash) in &update.block_hashes { + batch.put_extras(number, hash); + write_hashes.remove(number); + } + + for (hash, tx_address) in &update.transactions_addresses { + batch.put_extras(hash, tx_address); + write_txs.remove(hash); + } + + // update extras database + self.extras_db.write(batch).unwrap(); + } + } + + /// Iterator that lists `first` and then all of `first`'s ancestors, by hash. + pub fn ancestry_iter(&self, first: H256) -> Option { + if self.is_known(&first) { + Some(AncestryIter { + current: first, + chain: &self, + }) + } else { + None + } + } + + /// Given a block's `parent`, find every block header which represents a valid possible uncle. + pub fn find_uncle_headers(&self, parent: &H256, uncle_generations: usize) -> Option> { + if !self.is_known(parent) { return None; } + + let mut excluded = HashSet::new(); + for a in self.ancestry_iter(parent.clone()).unwrap().take(uncle_generations) { + excluded.extend(self.uncle_hashes(&a).unwrap().into_iter()); + excluded.insert(a); + } + + let mut ret = Vec::new(); + for a in self.ancestry_iter(parent.clone()).unwrap().skip(1).take(uncle_generations) { + ret.extend(self.block_details(&a).unwrap().children.iter() + .filter_map(|h| if excluded.contains(h) { None } else { self.block_header(h) }) + ); + } + Some(ret) + } + + /// Get inserted block info which is critical to preapre extras updates. + fn block_info(&self, block_bytes: &[u8]) -> BlockInfo { + let block = BlockView::new(block_bytes); + let header = block.header_view(); + let hash = block.sha3(); + let number = header.number(); + let parent_hash = header.parent_hash(); + let parent_details = self.block_details(&parent_hash).expect(format!("Invalid parent hash: {:?}", parent_hash).as_ref()); + let total_difficulty = parent_details.total_difficulty + header.difficulty(); + let is_new_best = total_difficulty > self.best_block_total_difficulty(); + + BlockInfo { + hash: hash, + number: number, + total_difficulty: total_difficulty, + location: if is_new_best { + // on new best block we need to make sure that all ancestors + // are moved to "canon chain" + // find the route between old best block and the new one + let best_hash = self.best_block_hash(); + let route = self.tree_route(best_hash, parent_hash); + + assert_eq!(number, parent_details.number + 1); + + match route.blocks.len() { + 0 => BlockLocation::CanonChain, + _ => { + let retracted = route.blocks.iter().take(route.index).cloned().collect::>(); + + BlockLocation::BranchBecomingCanonChain { + ancestor: route.ancestor, + enacted: route.blocks.into_iter().skip(route.index).collect(), + retracted: retracted.into_iter().rev().collect(), + } + } + } + } else { + BlockLocation::Branch + } + } + } + + /// This function returns modified block hashes. + fn prepare_block_hashes_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { + let mut block_hashes = HashMap::new(); + let block = BlockView::new(block_bytes); + let header = block.header_view(); + let number = header.number(); + + match info.location { + BlockLocation::Branch => (), + BlockLocation::CanonChain => { + block_hashes.insert(number, info.hash.clone()); + }, + BlockLocation::BranchBecomingCanonChain { ref ancestor, ref enacted, .. } => { + let ancestor_number = self.block_number(ancestor).unwrap(); + let start_number = ancestor_number + 1; + + for (index, hash) in enacted.iter().cloned().enumerate() { + block_hashes.insert(start_number + index as BlockNumber, hash); + } + + block_hashes.insert(number, info.hash.clone()); + } + } + + block_hashes + } + + /// This function returns modified block details. + fn prepare_block_details_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { + let block = BlockView::new(block_bytes); + let header = block.header_view(); + let parent_hash = header.parent_hash(); + + // update parent + let mut parent_details = self.block_details(&parent_hash).expect(format!("Invalid parent hash: {:?}", parent_hash).as_ref()); + parent_details.children.push(info.hash.clone()); + + // create current block details + let details = BlockDetails { + number: header.number(), + total_difficulty: info.total_difficulty, + parent: parent_hash.clone(), + children: vec![] + }; + + // write to batch + let mut block_details = HashMap::new(); + block_details.insert(parent_hash, parent_details); + block_details.insert(info.hash.clone(), details); + block_details + } + + /// This function returns modified block receipts. + fn prepare_block_receipts_update(&self, receipts: Vec, info: &BlockInfo) -> HashMap { + let mut block_receipts = HashMap::new(); + block_receipts.insert(info.hash.clone(), BlockReceipts::new(receipts)); + block_receipts + } + + /// This function returns modified transaction addresses. + fn prepare_transaction_addresses_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { + let block = BlockView::new(block_bytes); + let transaction_hashes = block.transaction_hashes(); + + transaction_hashes.into_iter() + .enumerate() + .fold(HashMap::new(), |mut acc, (i ,tx_hash)| { + acc.insert(tx_hash, TransactionAddress { + block_hash: info.hash.clone(), + index: i + }); + acc + }) + } + + /// This functions returns modified blocks blooms. + /// + /// To accelerate blooms lookups, blomms are stored in multiple + /// layers (BLOOM_LEVELS, currently 3). + /// ChainFilter is responsible for building and rebuilding these layers. + /// It returns them in HashMap, where values are Blooms and + /// keys are BloomIndexes. BloomIndex represents bloom location on one + /// of these layers. + /// + /// To reduce number of queries to databse, block blooms are stored + /// in BlocksBlooms structure which contains info about several + /// (BLOOM_INDEX_SIZE, currently 16) consecutive blocks blooms. + /// + /// Later, BloomIndexer is used to map bloom location on filter layer (BloomIndex) + /// to bloom location in database (BlocksBloomLocation). + /// + fn prepare_block_blooms_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { + let block = BlockView::new(block_bytes); + let header = block.header_view(); + + let modified_blooms = match info.location { + BlockLocation::Branch => HashMap::new(), + BlockLocation::CanonChain => { + ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels()) + .add_bloom(&header.log_bloom(), header.number() as usize) + }, + BlockLocation::BranchBecomingCanonChain { ref ancestor, ref enacted, .. } => { + let ancestor_number = self.block_number(ancestor).unwrap(); + let start_number = ancestor_number + 1; + + let mut blooms: Vec = enacted.iter() + .map(|hash| self.block(hash).unwrap()) + .map(|bytes| BlockView::new(&bytes).header_view().log_bloom()) + .collect(); + + blooms.push(header.log_bloom()); + + ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels()) + .reset_chain_head(&blooms, start_number as usize, self.best_block_number() as usize) + } + }; + + modified_blooms.into_iter() + .fold(HashMap::new(), | mut acc, (bloom_index, bloom) | { + { + let location = self.bloom_indexer.location(&bloom_index); + let mut blocks_blooms = acc + .entry(location.hash.clone()) + .or_insert_with(|| self.blocks_blooms(&location.hash).unwrap_or_else(BlocksBlooms::new)); + assert_eq!(self.bloom_indexer.index_size(), blocks_blooms.blooms.len()); + blocks_blooms.blooms[location.index] = bloom; + } + acc + }) + } + + /// Get best block hash. + pub fn best_block_hash(&self) -> H256 { + self.best_block.read().unwrap().hash.clone() + } + + /// Get best block number. + pub fn best_block_number(&self) -> BlockNumber { + self.best_block.read().unwrap().number + } + + /// Get best block total difficulty. + pub fn best_block_total_difficulty(&self) -> U256 { + self.best_block.read().unwrap().total_difficulty + } + + /// Get block blooms. + fn blocks_blooms(&self, hash: &H256) -> Option { + self.query_extras(hash, &self.blocks_blooms) + } + + fn query_extras(&self, hash: &K, cache: &RwLock>) -> Option where + T: Clone + Decodable + ExtrasIndexable, + K: ExtrasSliceConvertable + Eq + Hash + Clone { + { + let read = cache.read().unwrap(); + if let Some(v) = read.get(hash) { + return Some(v.clone()); + } + } + + if let Some(h) = hash.as_h256() { + self.note_used(CacheID::Extras(T::extras_index(), h.clone())); + } + + self.extras_db.get_extras(hash).map(| t: T | { + let mut write = cache.write().unwrap(); + write.insert(hash.clone(), t.clone()); + t + }) + } + + fn query_extras_exist(&self, hash: &K, cache: &RwLock>) -> bool where + K: ExtrasSliceConvertable + Eq + Hash + Clone, + T: ExtrasIndexable { + { + let read = cache.read().unwrap(); + if let Some(_) = read.get(hash) { + return true; + } + } + + self.extras_db.extras_exists::<_, T>(hash) + } + + /// Get current cache size. + pub fn cache_size(&self) -> CacheSize { + CacheSize { + blocks: self.blocks.read().unwrap().heap_size_of_children(), + block_details: self.block_details.read().unwrap().heap_size_of_children(), + transaction_addresses: self.transaction_addresses.read().unwrap().heap_size_of_children(), + block_logs: self.block_logs.read().unwrap().heap_size_of_children(), + blocks_blooms: self.blocks_blooms.read().unwrap().heap_size_of_children(), + block_receipts: self.block_receipts.read().unwrap().heap_size_of_children() + } + } + + /// Let the cache system know that a cacheable item has been used. + fn note_used(&self, id: CacheID) { + let mut cache_man = self.cache_man.write().unwrap(); + if !cache_man.cache_usage[0].contains(&id) { + cache_man.cache_usage[0].insert(id.clone()); + if cache_man.in_use.contains(&id) { + if let Some(c) = cache_man.cache_usage.iter_mut().skip(1).find(|e|e.contains(&id)) { + c.remove(&id); + } + } else { + cache_man.in_use.insert(id); + } + } + } + + /// Ticks our cache system and throws out any old data. + pub fn collect_garbage(&self) { + if self.cache_size().total() < self.pref_cache_size.load(AtomicOrder::Relaxed) { return; } + + for _ in 0..COLLECTION_QUEUE_SIZE { + { + let mut blocks = self.blocks.write().unwrap(); + let mut block_details = self.block_details.write().unwrap(); + let mut block_hashes = self.block_hashes.write().unwrap(); + let mut transaction_addresses = self.transaction_addresses.write().unwrap(); + let mut block_logs = self.block_logs.write().unwrap(); + let mut blocks_blooms = self.blocks_blooms.write().unwrap(); + let mut block_receipts = self.block_receipts.write().unwrap(); + let mut cache_man = self.cache_man.write().unwrap(); + + for id in cache_man.cache_usage.pop_back().unwrap().into_iter() { + cache_man.in_use.remove(&id); + match id { + CacheID::Block(h) => { blocks.remove(&h); }, + CacheID::Extras(ExtrasIndex::BlockDetails, h) => { block_details.remove(&h); }, + CacheID::Extras(ExtrasIndex::TransactionAddress, h) => { transaction_addresses.remove(&h); }, + CacheID::Extras(ExtrasIndex::BlockLogBlooms, h) => { block_logs.remove(&h); }, + CacheID::Extras(ExtrasIndex::BlocksBlooms, h) => { blocks_blooms.remove(&h); }, + CacheID::Extras(ExtrasIndex::BlockReceipts, h) => { block_receipts.remove(&h); }, + _ => panic!(), + } + } + cache_man.cache_usage.push_front(HashSet::new()); + + // TODO: handle block_hashes properly. + block_hashes.clear(); + + blocks.shrink_to_fit(); + block_details.shrink_to_fit(); + block_hashes.shrink_to_fit(); + transaction_addresses.shrink_to_fit(); + block_logs.shrink_to_fit(); + blocks_blooms.shrink_to_fit(); + block_receipts.shrink_to_fit(); + } + if self.cache_size().total() < self.max_cache_size.load(AtomicOrder::Relaxed) { break; } + } + + // TODO: m_lastCollection = chrono::system_clock::now(); + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + use rustc_serialize::hex::FromHex; + use util::hash::*; + use util::sha3::Hashable; + use blockchain::{BlockProvider, BlockChain, BlockChainConfig, ImportRoute}; + use tests::helpers::*; + use devtools::*; + use blockchain::generator::{ChainGenerator, ChainIterator, BlockFinalizer}; + use views::BlockView; + + #[test] + fn basic_blockchain_insert() { + let mut canon_chain = ChainGenerator::default(); + let mut finalizer = BlockFinalizer::default(); + let genesis = canon_chain.generate(&mut finalizer).unwrap(); + let first = canon_chain.generate(&mut finalizer).unwrap(); + let genesis_hash = BlockView::new(&genesis).header_view().sha3(); + let first_hash = BlockView::new(&first).header_view().sha3(); + + let temp = RandomTempPath::new(); + let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); + + assert_eq!(bc.genesis_hash(), genesis_hash.clone()); + assert_eq!(bc.best_block_number(), 0); + assert_eq!(bc.best_block_hash(), genesis_hash.clone()); + assert_eq!(bc.block_hash(0), Some(genesis_hash.clone())); + assert_eq!(bc.block_hash(1), None); + assert_eq!(bc.block_details(&genesis_hash).unwrap().children, vec![]); + + bc.insert_block(&first, vec![]); + + assert_eq!(bc.block_hash(0), Some(genesis_hash.clone())); + assert_eq!(bc.best_block_number(), 1); + assert_eq!(bc.best_block_hash(), first_hash.clone()); + assert_eq!(bc.block_hash(1), Some(first_hash.clone())); + assert_eq!(bc.block_details(&first_hash).unwrap().parent, genesis_hash.clone()); + assert_eq!(bc.block_details(&genesis_hash).unwrap().children, vec![first_hash.clone()]); + assert_eq!(bc.block_hash(2), None); + } + + #[test] + fn check_ancestry_iter() { + let mut canon_chain = ChainGenerator::default(); + let mut finalizer = BlockFinalizer::default(); + let genesis = canon_chain.generate(&mut finalizer).unwrap(); + let genesis_hash = BlockView::new(&genesis).header_view().sha3(); + + let temp = RandomTempPath::new(); + let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); + + let mut block_hashes = vec![genesis_hash.clone()]; + for _ in 0..10 { + let block = canon_chain.generate(&mut finalizer).unwrap(); + block_hashes.push(BlockView::new(&block).header_view().sha3()); + bc.insert_block(&block, vec![]); + } + + block_hashes.reverse(); + + assert_eq!(bc.ancestry_iter(block_hashes[0].clone()).unwrap().collect::>(), block_hashes) + } + + #[test] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] + fn test_find_uncles() { + let mut canon_chain = ChainGenerator::default(); + let mut finalizer = BlockFinalizer::default(); + let genesis = canon_chain.generate(&mut finalizer).unwrap(); + let b1b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap(); + let b1a = canon_chain.generate(&mut finalizer).unwrap(); + let b2b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap(); + let b2a = canon_chain.generate(&mut finalizer).unwrap(); + let b3b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap(); + let b3a = canon_chain.generate(&mut finalizer).unwrap(); + let b4b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap(); + let b4a = canon_chain.generate(&mut finalizer).unwrap(); + let b5b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap(); + let b5a = canon_chain.generate(&mut finalizer).unwrap(); + + let temp = RandomTempPath::new(); + let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); + bc.insert_block(&b1a, vec![]); + bc.insert_block(&b1b, vec![]); + bc.insert_block(&b2a, vec![]); + bc.insert_block(&b2b, vec![]); + bc.insert_block(&b3a, vec![]); + bc.insert_block(&b3b, vec![]); + bc.insert_block(&b4a, vec![]); + bc.insert_block(&b4b, vec![]); + bc.insert_block(&b5a, vec![]); + bc.insert_block(&b5b, vec![]); + + assert_eq!( + [&b4b, &b3b, &b2b].iter().map(|b| BlockView::new(b).header()).collect::>(), + bc.find_uncle_headers(&BlockView::new(&b4a).header_view().sha3(), 3).unwrap() + ); + + // TODO: insert block that already includes one of them as an uncle to check it's not allowed. + } + + #[test] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] + fn test_small_fork() { + let mut canon_chain = ChainGenerator::default(); + let mut finalizer = BlockFinalizer::default(); + let genesis = canon_chain.generate(&mut finalizer).unwrap(); + let b1 = canon_chain.generate(&mut finalizer).unwrap(); + let b2 = canon_chain.generate(&mut finalizer).unwrap(); + let b3b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap(); + let b3a = canon_chain.generate(&mut finalizer).unwrap(); + + let genesis_hash = BlockView::new(&genesis).header_view().sha3(); + let b1_hash= BlockView::new(&b1).header_view().sha3(); + let b2_hash= BlockView::new(&b2).header_view().sha3(); + let b3a_hash= BlockView::new(&b3a).header_view().sha3(); + let b3b_hash= BlockView::new(&b3b).header_view().sha3(); + + // b3a is a part of canon chain, whereas b3b is part of sidechain + let best_block_hash = b3a_hash.clone(); + + let temp = RandomTempPath::new(); + let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); + let ir1 = bc.insert_block(&b1, vec![]); + let ir2 = bc.insert_block(&b2, vec![]); + let ir3b = bc.insert_block(&b3b, vec![]); + let ir3a = bc.insert_block(&b3a, vec![]); + + assert_eq!(ir1, ImportRoute { + enacted: vec![b1_hash], + retracted: vec![], + }); + + assert_eq!(ir2, ImportRoute { + enacted: vec![b2_hash], + retracted: vec![], + }); + + assert_eq!(ir3b, ImportRoute { + enacted: vec![b3b_hash], + retracted: vec![], + }); + + assert_eq!(ir3a, ImportRoute { + enacted: vec![b3a_hash], + retracted: vec![b3b_hash], + }); + + assert_eq!(bc.best_block_hash(), best_block_hash); + assert_eq!(bc.block_number(&genesis_hash).unwrap(), 0); + assert_eq!(bc.block_number(&b1_hash).unwrap(), 1); + assert_eq!(bc.block_number(&b2_hash).unwrap(), 2); + assert_eq!(bc.block_number(&b3a_hash).unwrap(), 3); + assert_eq!(bc.block_number(&b3b_hash).unwrap(), 3); + + assert_eq!(bc.block_hash(0).unwrap(), genesis_hash); + assert_eq!(bc.block_hash(1).unwrap(), b1_hash); + assert_eq!(bc.block_hash(2).unwrap(), b2_hash); + assert_eq!(bc.block_hash(3).unwrap(), b3a_hash); + + // test trie route + let r0_1 = bc.tree_route(genesis_hash.clone(), b1_hash.clone()); + assert_eq!(r0_1.ancestor, genesis_hash); + assert_eq!(r0_1.blocks, [b1_hash.clone()]); + assert_eq!(r0_1.index, 0); + + let r0_2 = bc.tree_route(genesis_hash.clone(), b2_hash.clone()); + assert_eq!(r0_2.ancestor, genesis_hash); + assert_eq!(r0_2.blocks, [b1_hash.clone(), b2_hash.clone()]); + assert_eq!(r0_2.index, 0); + + let r1_3a = bc.tree_route(b1_hash.clone(), b3a_hash.clone()); + assert_eq!(r1_3a.ancestor, b1_hash); + assert_eq!(r1_3a.blocks, [b2_hash.clone(), b3a_hash.clone()]); + assert_eq!(r1_3a.index, 0); + + let r1_3b = bc.tree_route(b1_hash.clone(), b3b_hash.clone()); + assert_eq!(r1_3b.ancestor, b1_hash); + assert_eq!(r1_3b.blocks, [b2_hash.clone(), b3b_hash.clone()]); + assert_eq!(r1_3b.index, 0); + + let r3a_3b = bc.tree_route(b3a_hash.clone(), b3b_hash.clone()); + assert_eq!(r3a_3b.ancestor, b2_hash); + assert_eq!(r3a_3b.blocks, [b3a_hash.clone(), b3b_hash.clone()]); + assert_eq!(r3a_3b.index, 1); + + let r1_0 = bc.tree_route(b1_hash.clone(), genesis_hash.clone()); + assert_eq!(r1_0.ancestor, genesis_hash); + assert_eq!(r1_0.blocks, [b1_hash.clone()]); + assert_eq!(r1_0.index, 1); + + let r2_0 = bc.tree_route(b2_hash.clone(), genesis_hash.clone()); + assert_eq!(r2_0.ancestor, genesis_hash); + assert_eq!(r2_0.blocks, [b2_hash.clone(), b1_hash.clone()]); + assert_eq!(r2_0.index, 2); + + let r3a_1 = bc.tree_route(b3a_hash.clone(), b1_hash.clone()); + assert_eq!(r3a_1.ancestor, b1_hash); + assert_eq!(r3a_1.blocks, [b3a_hash.clone(), b2_hash.clone()]); + assert_eq!(r3a_1.index, 2); + + let r3b_1 = bc.tree_route(b3b_hash.clone(), b1_hash.clone()); + assert_eq!(r3b_1.ancestor, b1_hash); + assert_eq!(r3b_1.blocks, [b3b_hash.clone(), b2_hash.clone()]); + assert_eq!(r3b_1.index, 2); + + let r3b_3a = bc.tree_route(b3b_hash.clone(), b3a_hash.clone()); + assert_eq!(r3b_3a.ancestor, b2_hash); + assert_eq!(r3b_3a.blocks, [b3b_hash.clone(), b3a_hash.clone()]); + assert_eq!(r3b_3a.index, 1); + } + + #[test] + fn test_reopen_blockchain_db() { + let mut canon_chain = ChainGenerator::default(); + let mut finalizer = BlockFinalizer::default(); + let genesis = canon_chain.generate(&mut finalizer).unwrap(); + let first = canon_chain.generate(&mut finalizer).unwrap(); + let genesis_hash = BlockView::new(&genesis).header_view().sha3(); + let first_hash = BlockView::new(&first).header_view().sha3(); + + let temp = RandomTempPath::new(); + { + let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); + assert_eq!(bc.best_block_hash(), genesis_hash); + bc.insert_block(&first, vec![]); + assert_eq!(bc.best_block_hash(), first_hash); + } + + { + let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); + assert_eq!(bc.best_block_hash(), first_hash); + } + } + + #[test] + fn can_contain_arbitrary_block_sequence() { + let bc_result = generate_dummy_blockchain(50); + let bc = bc_result.reference(); + assert_eq!(bc.best_block_number(), 49); + } + + #[test] + fn can_collect_garbage() { + let bc_result = generate_dummy_blockchain(3000); + let bc = bc_result.reference(); + + assert_eq!(bc.best_block_number(), 2999); + let best_hash = bc.best_block_hash(); + let mut block_header = bc.block_header(&best_hash); + + while !block_header.is_none() { + block_header = bc.block_header(&block_header.unwrap().parent_hash); + } + assert!(bc.cache_size().blocks > 1024 * 1024); + + for _ in 0..2 { + bc.collect_garbage(); + } + assert!(bc.cache_size().blocks < 1024 * 1024); + } + + #[test] + fn can_contain_arbitrary_block_sequence_with_extra() { + let bc_result = generate_dummy_blockchain_with_extra(25); + let bc = bc_result.reference(); + assert_eq!(bc.best_block_number(), 24); + } + + #[test] + fn can_contain_only_genesis_block() { + let bc_result = generate_dummy_empty_blockchain(); + let bc = bc_result.reference(); + assert_eq!(bc.best_block_number(), 0); + } + + #[test] + fn find_transaction_by_hash() { + let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0af81e09f8c46ca322193edfda764fa7e88e81923f802f1d325ec0b0308ac2cd0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200008083023e38808454c98c8142a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421880102030405060708c0c0".from_hex().unwrap(); + let b1 = "f904a8f901faa0ce1f26f798dd03c8782d63b3e42e79a64eaea5694ea686ac5d7ce3df5171d1aea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0a65c2364cd0f1542d761823dc0109c6b072f14c20459598c5455c274601438f4a070616ebd7ad2ed6fb7860cf7e9df00163842351c38a87cac2c1cb193895035a2a05c5b4fc43c2d45787f54e1ae7d27afdb4ad16dfc567c5692070d5c4556e0b1d7b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200000183023ec683021536845685109780a029f07836e4e59229b3a065913afc27702642c683bba689910b2b2fd45db310d3888957e6d004a31802f902a7f85f800a8255f094aaaf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca0575da4e21b66fa764be5f74da9389e67693d066fb0d1312e19e17e501da00ecda06baf5a5327595f6619dfc2fcb3f2e6fb410b5810af3cb52d0e7508038e91a188f85f010a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba04fa966bf34b93abc1bcd665554b7f316b50f928477b50be0f3285ead29d18c5ba017bba0eeec1625ab433746955e125d46d80b7fdc97386c51266f842d8e02192ef85f020a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca004377418ae981cc32b1312b4a427a1d69a821b28db8584f5f2bd8c6d42458adaa053a1dba1af177fac92f3b6af0a9fa46a22adf56e686c93794b6a012bf254abf5f85f030a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ca04fe13febd28a05f4fcb2f451d7ddc2dda56486d9f8c79a62b0ba4da775122615a0651b2382dd402df9ebc27f8cb4b2e0f3cea68dda2dca0ee9603608f0b6f51668f85f040a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba078e6a0ba086a08f8450e208a399bb2f2d2a0d984acd2517c7c7df66ccfab567da013254002cd45a97fac049ae00afbc43ed0d9961d0c56a3b2382c80ce41c198ddf85f050a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba0a7174d8f43ea71c8e3ca9477691add8d80ac8e0ed89d8d8b572041eef81f4a54a0534ea2e28ec4da3b5b944b18c51ec84a5cf35f5b3343c5fb86521fd2d388f506f85f060a82520894bbbf5374fce5edbc8e2a8697c15331677e6ebf0b0a801ba034bd04065833536a10c77ee2a43a5371bc6d34837088b861dd9d4b7f44074b59a078807715786a13876d3455716a6b9cb2186b7a4887a5c31160fc877454958616c0".from_hex().unwrap(); + let b1_hash = H256::from_str("f53f268d23a71e85c7d6d83a9504298712b84c1a2ba220441c86eeda0bf0b6e3").unwrap(); + + let temp = RandomTempPath::new(); + let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); + bc.insert_block(&b1, vec![]); + + let transactions = bc.transactions(&b1_hash).unwrap(); + assert_eq!(transactions.len(), 7); + for t in transactions { + assert_eq!(bc.transaction(&bc.transaction_address(&t.hash()).unwrap()).unwrap(), t); + } + } + + #[test] + fn test_bloom_filter_simple() { + // TODO: From here + let bloom_b1 = H2048::from_str("00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000").unwrap(); + + let bloom_b2 = H2048::from_str("00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); + + let bloom_ba = H2048::from_str("00000000000000000000000000000000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); + + let mut canon_chain = ChainGenerator::default(); + let mut finalizer = BlockFinalizer::default(); + let genesis = canon_chain.generate(&mut finalizer).unwrap(); + let mut fork = canon_chain.fork(1); + let mut fork_finalizer = finalizer.fork(); + let b1 = fork.with_bloom(bloom_b1.clone()).generate(&mut fork_finalizer).unwrap(); + let b2 = fork.with_bloom(bloom_b2.clone()).generate(&mut fork_finalizer).unwrap(); + let b3 = fork.with_bloom(bloom_ba.clone()).generate(&mut fork_finalizer).unwrap(); + let b1a = canon_chain.with_bloom(bloom_ba.clone()).generate(&mut finalizer).unwrap(); + let b2a = canon_chain.with_bloom(bloom_ba.clone()).generate(&mut finalizer).unwrap(); + + let temp = RandomTempPath::new(); + let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); + + let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); + let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); + assert_eq!(blocks_b1, vec![]); + assert_eq!(blocks_b2, vec![]); + + bc.insert_block(&b1, vec![]); + let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); + let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); + assert_eq!(blocks_b1, vec![1]); + assert_eq!(blocks_b2, vec![]); + + bc.insert_block(&b2, vec![]); + let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); + let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); + assert_eq!(blocks_b1, vec![1]); + assert_eq!(blocks_b2, vec![2]); + + // hasn't been forked yet + bc.insert_block(&b1a, vec![]); + let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); + let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); + let blocks_ba = bc.blocks_with_bloom(&bloom_ba, 0, 5); + assert_eq!(blocks_b1, vec![1]); + assert_eq!(blocks_b2, vec![2]); + assert_eq!(blocks_ba, vec![]); + + // fork has happend + bc.insert_block(&b2a, vec![]); + let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); + let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); + let blocks_ba = bc.blocks_with_bloom(&bloom_ba, 0, 5); + assert_eq!(blocks_b1, vec![]); + assert_eq!(blocks_b2, vec![]); + assert_eq!(blocks_ba, vec![1, 2]); + + // fork back + bc.insert_block(&b3, vec![]); + let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); + let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); + let blocks_ba = bc.blocks_with_bloom(&bloom_ba, 0, 5); + assert_eq!(blocks_b1, vec![1]); + assert_eq!(blocks_b2, vec![2]); + assert_eq!(blocks_ba, vec![3]); + } +} diff --git a/ethcore/src/blockchain/bloom_indexer.rs b/ethcore/src/blockchain/bloom_indexer.rs new file mode 100644 index 000000000..a672a5445 --- /dev/null +++ b/ethcore/src/blockchain/bloom_indexer.rs @@ -0,0 +1,102 @@ +// 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::H256; +use chainfilter::BloomIndex; + +/// Represents location of block bloom in extras database. +#[derive(Debug, PartialEq)] +pub struct BlocksBloomLocation { + /// Unique hash of BlocksBloom + pub hash: H256, + /// Index within BlocksBloom + pub index: usize, +} + +/// Should be used to localize blocks blooms in extras database. +pub struct BloomIndexer { + index_size: usize, + levels: u8, +} + +impl BloomIndexer { + /// Plain constructor. + pub fn new(index_size: usize, levels: u8) -> Self { + BloomIndexer { + index_size: index_size, + levels: levels + } + } + + /// Calculates bloom's position in database. + pub fn location(&self, bloom_index: &BloomIndex) -> BlocksBloomLocation { + use std::{mem, ptr}; + + let hash = unsafe { + let mut hash: H256 = mem::zeroed(); + ptr::copy(&[bloom_index.index / self.index_size] as *const usize as *const u8, hash.as_mut_ptr(), 8); + hash[8] = bloom_index.level; + hash.reverse(); + hash + }; + + BlocksBloomLocation { + hash: hash, + index: bloom_index.index % self.index_size + } + } + + /// Returns index size. + pub fn index_size(&self) -> usize { + self.index_size + } + + /// Returns number of cache levels. + pub fn levels(&self) -> u8 { + self.levels + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + use util::hash::{H256, FixedHash}; + use chainfilter::BloomIndex; + use blockchain::bloom_indexer::{BloomIndexer, BlocksBloomLocation}; + + #[test] + fn test_bloom_indexer() { + let bi = BloomIndexer::new(16, 3); + + let index = BloomIndex::new(0, 0); + assert_eq!(bi.location(&index), BlocksBloomLocation { + hash: H256::new(), + index: 0 + }); + + let index = BloomIndex::new(1, 0); + assert_eq!(bi.location(&index), BlocksBloomLocation { + hash: H256::from_str("0000000000000000000000000000000000000000000000010000000000000000").unwrap(), + index: 0 + }); + + let index = BloomIndex::new(0, 299_999); + assert_eq!(bi.location(&index), BlocksBloomLocation { + hash: H256::from_str("000000000000000000000000000000000000000000000000000000000000493d").unwrap(), + index: 15 + }); + } +} diff --git a/ethcore/src/blockchain/cache.rs b/ethcore/src/blockchain/cache.rs new file mode 100644 index 000000000..722f83c16 --- /dev/null +++ b/ethcore/src/blockchain/cache.rs @@ -0,0 +1,37 @@ +// 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 . + +/// Represents blockchain's in-memory cache size in bytes. +#[derive(Debug)] +pub struct CacheSize { + /// Blocks cache size. + pub blocks: usize, + /// BlockDetails cache size. + pub block_details: usize, + /// Transaction addresses cache size. + pub transaction_addresses: usize, + /// Logs cache size. + pub block_logs: usize, + /// Blooms cache size. + pub blocks_blooms: usize, + /// Block receipts size. + pub block_receipts: usize, +} + +impl CacheSize { + /// Total amount used by the cache. + pub fn total(&self) -> usize { self.blocks + self.block_details + self.transaction_addresses + self.block_logs + self.blocks_blooms } +} diff --git a/ethcore/src/blockchain/generator/block.rs b/ethcore/src/blockchain/generator/block.rs new file mode 100644 index 000000000..0a3dad399 --- /dev/null +++ b/ethcore/src/blockchain/generator/block.rs @@ -0,0 +1,64 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use util::rlp::*; +use util::{H256, H2048}; +use util::U256; +use util::bytes::Bytes; +use header::Header; +use transaction::SignedTransaction; + +use super::fork::Forkable; +use super::bloom::WithBloom; +use super::complete::CompleteBlock; + +/// Helper structure, used for encoding blocks. +#[derive(Default)] +pub struct Block { + pub header: Header, + pub transactions: Vec, + pub uncles: Vec
+} + +impl Encodable for Block { + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(3); + s.append(&self.header); + s.append(&self.transactions); + s.append(&self.uncles); + } +} + +impl Forkable for Block { + fn fork(mut self, fork_number: usize) -> Self where Self: Sized { + self.header.difficulty = self.header.difficulty - U256::from(fork_number); + self + } +} + +impl WithBloom for Block { + fn with_bloom(mut self, bloom: H2048) -> Self where Self: Sized { + self.header.log_bloom = bloom; + self + } +} + +impl CompleteBlock for Block { + fn complete(mut self, parent_hash: H256) -> Bytes { + self.header.parent_hash = parent_hash; + encode(&self).to_vec() + } +} diff --git a/ethcore/src/blockchain/generator/bloom.rs b/ethcore/src/blockchain/generator/bloom.rs new file mode 100644 index 000000000..f61c9d1ff --- /dev/null +++ b/ethcore/src/blockchain/generator/bloom.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 . + +use util::hash::H2048; + +pub trait WithBloom { + fn with_bloom(self, bloom: H2048) -> Self where Self: Sized; +} + +pub struct Bloom<'a, I> where I: 'a { + pub iter: &'a mut I, + pub bloom: H2048, +} + +impl<'a, I> Iterator for Bloom<'a, I> where I: Iterator, ::Item: WithBloom { + type Item = ::Item; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next().map(|item| item.with_bloom(self.bloom.clone())) + } +} diff --git a/ethcore/src/blockchain/generator/complete.rs b/ethcore/src/blockchain/generator/complete.rs new file mode 100644 index 000000000..39bd587a0 --- /dev/null +++ b/ethcore/src/blockchain/generator/complete.rs @@ -0,0 +1,53 @@ +// 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::hash::H256; +use util::bytes::Bytes; +use util::sha3::Hashable; +use views::BlockView; + +#[derive(Default, Clone)] +pub struct BlockFinalizer { + parent_hash: H256 +} + +impl BlockFinalizer { + pub fn fork(&self) -> Self { + self.clone() + } +} + +pub trait CompleteBlock { + fn complete(self, parent_hash: H256) -> Bytes; +} + +pub struct Complete<'a, I> where I: 'a { + pub iter: &'a mut I, + pub finalizer: &'a mut BlockFinalizer, +} + +impl<'a, I> Iterator for Complete<'a, I> where I: Iterator, ::Item: CompleteBlock { + type Item = Bytes; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next().map(|item| { + let rlp = item.complete(self.finalizer.parent_hash.clone()); + self.finalizer.parent_hash = BlockView::new(&rlp).header_view().sha3(); + rlp + }) + } +} diff --git a/ethcore/src/blockchain/generator/fork.rs b/ethcore/src/blockchain/generator/fork.rs new file mode 100644 index 000000000..f3a4eb267 --- /dev/null +++ b/ethcore/src/blockchain/generator/fork.rs @@ -0,0 +1,42 @@ +// 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 . + +pub trait Forkable { + fn fork(self, fork_number: usize) -> Self where Self: Sized; +} + +pub struct Fork { + pub iter: I, + pub fork_number: usize, +} + +impl Clone for Fork where I: Iterator + Clone { + fn clone(&self) -> Self { + Fork { + iter: self.iter.clone(), + fork_number: self.fork_number + } + } +} + +impl Iterator for Fork where I: Iterator, ::Item: Forkable { + type Item = ::Item; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next().map(|item| item.fork(self.fork_number)) + } +} diff --git a/ethcore/src/blockchain/generator/generator.rs b/ethcore/src/blockchain/generator/generator.rs new file mode 100644 index 000000000..88c9577e2 --- /dev/null +++ b/ethcore/src/blockchain/generator/generator.rs @@ -0,0 +1,169 @@ +// 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::hash::H2048; +use util::numbers::U256; +use util::bytes::Bytes; +use header::BlockNumber; +use super::fork::Fork; +use super::bloom::Bloom; +use super::complete::{BlockFinalizer, CompleteBlock, Complete}; +use super::block::Block; + +/// Chain iterator interface. +pub trait ChainIterator: Iterator + Sized { + /// Should be called to create a fork of current iterator. + /// Blocks generated by fork will have lower difficulty than current chain. + fn fork(&self, fork_number: usize) -> Fork where Self: Clone; + /// Should be called to make every consecutive block have given bloom. + fn with_bloom(&mut self, bloom: H2048) -> Bloom; + /// Should be called to complete block. Without complete, block may have incorrect hash. + fn complete<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Complete<'a, Self>; + /// Completes and generates block. + fn generate<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Option where Self::Item: CompleteBlock; +} + +impl ChainIterator for I where I: Iterator + Sized { + fn fork(&self, fork_number: usize) -> Fork where I: Clone { + Fork { + iter: self.clone(), + fork_number: fork_number + } + } + + fn with_bloom(&mut self, bloom: H2048) -> Bloom { + Bloom { + iter: self, + bloom: bloom + } + } + + fn complete<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Complete<'a, Self> { + Complete { + iter: self, + finalizer: finalizer + } + } + + fn generate<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Option where ::Item: CompleteBlock { + self.complete(finalizer).next() + } +} + +/// Blockchain generator. +#[derive(Clone)] +pub struct ChainGenerator { + /// Next block number. + number: BlockNumber, + /// Next block difficulty. + difficulty: U256, +} + +impl ChainGenerator { + fn prepare_block(&self) -> Block { + let mut block = Block::default(); + block.header.number = self.number; + block.header.difficulty = self.difficulty; + block + } +} + +impl Default for ChainGenerator { + fn default() -> Self { + ChainGenerator { + number: 0, + difficulty: U256::from(1000), + } + } +} + +impl Iterator for ChainGenerator { + type Item = Block; + + fn next(&mut self) -> Option { + let block = self.prepare_block(); + self.number += 1; + Some(block) + } +} + +mod tests { + use util::hash::{H256, H2048}; + use util::sha3::Hashable; + use views::BlockView; + use blockchain::generator::{ChainIterator, ChainGenerator, BlockFinalizer}; + + #[test] + fn canon_chain_generator() { + let mut canon_chain = ChainGenerator::default(); + let mut finalizer = BlockFinalizer::default(); + + let genesis_rlp = canon_chain.generate(&mut finalizer).unwrap(); + let genesis = BlockView::new(&genesis_rlp); + + assert_eq!(genesis.header_view().parent_hash(), H256::default()); + assert_eq!(genesis.header_view().number(), 0); + + let b1_rlp = canon_chain.generate(&mut finalizer).unwrap(); + let b1 = BlockView::new(&b1_rlp); + + assert_eq!(b1.header_view().parent_hash(), genesis.header_view().sha3()); + assert_eq!(b1.header_view().number(), 1); + + let mut fork_chain = canon_chain.fork(1); + + let b2_rlp_fork = fork_chain.generate(&mut finalizer.fork()).unwrap(); + let b2_fork = BlockView::new(&b2_rlp_fork); + + assert_eq!(b2_fork.header_view().parent_hash(), b1.header_view().sha3()); + assert_eq!(b2_fork.header_view().number(), 2); + + let b2_rlp = canon_chain.generate(&mut finalizer).unwrap(); + let b2 = BlockView::new(&b2_rlp); + + assert_eq!(b2.header_view().parent_hash(), b1.header_view().sha3()); + assert_eq!(b2.header_view().number(), 2); + assert!(b2.header_view().difficulty() > b2_fork.header_view().difficulty()); + } + + #[test] + fn with_bloom_generator() { + let bloom = H2048([0x1; 256]); + let mut gen = ChainGenerator::default(); + let mut finalizer = BlockFinalizer::default(); + + let block0_rlp = gen.with_bloom(bloom).generate(&mut finalizer).unwrap(); + let block1_rlp = gen.generate(&mut finalizer).unwrap(); + let block0 = BlockView::new(&block0_rlp); + let block1 = BlockView::new(&block1_rlp); + + assert_eq!(block0.header_view().number(), 0); + assert_eq!(block0.header_view().parent_hash(), H256::default()); + + assert_eq!(block1.header_view().number(), 1); + assert_eq!(block1.header_view().parent_hash(), block0.header_view().sha3()); + + } + + #[test] + fn generate_1000_blocks() { + let generator = ChainGenerator::default(); + let mut finalizer = BlockFinalizer::default(); + let blocks: Vec<_> = generator.take(1000).complete(&mut finalizer).collect(); + assert_eq!(blocks.len(), 1000); + } +} + diff --git a/ethcore/src/blockchain/generator/mod.rs b/ethcore/src/blockchain/generator/mod.rs new file mode 100644 index 000000000..88fdec0e4 --- /dev/null +++ b/ethcore/src/blockchain/generator/mod.rs @@ -0,0 +1,24 @@ +// 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 . + +mod bloom; +mod block; +mod complete; +mod fork; +pub mod generator; + +pub use self::complete::BlockFinalizer; +pub use self::generator::{ChainIterator, ChainGenerator}; diff --git a/ethcore/src/blockchain/import_route.rs b/ethcore/src/blockchain/import_route.rs new file mode 100644 index 000000000..262b70899 --- /dev/null +++ b/ethcore/src/blockchain/import_route.rs @@ -0,0 +1,119 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Import route. + +use util::hash::H256; +use blockchain::block_info::{BlockInfo, BlockLocation}; + +/// Import route for newly inserted block. +#[derive(Debug, PartialEq)] +pub struct ImportRoute { + /// Blocks that were invalidated by new block. + pub retracted: Vec, + /// Blocks that were validated by new block. + pub enacted: Vec, +} + +impl ImportRoute { + pub fn none() -> Self { + ImportRoute { + retracted: vec![], + enacted: vec![], + } + } +} + +impl From for ImportRoute { + fn from(info: BlockInfo) -> ImportRoute { + match info.location { + BlockLocation::CanonChain => ImportRoute { + retracted: vec![], + enacted: vec![info.hash], + }, + BlockLocation::Branch => ImportRoute::none(), + BlockLocation::BranchBecomingCanonChain { mut enacted, retracted, .. } => { + enacted.push(info.hash); + ImportRoute { + retracted: retracted, + enacted: enacted, + } + } + } + } +} + +#[cfg(test)] +mod tests { + use util::hash::H256; + use util::numbers::U256; + use blockchain::block_info::{BlockInfo, BlockLocation}; + use blockchain::ImportRoute; + + #[test] + fn import_route_none() { + assert_eq!(ImportRoute::none(), ImportRoute { + enacted: vec![], + retracted: vec![], + }); + } + + #[test] + fn import_route_branch() { + let info = BlockInfo { + hash: H256::from(U256::from(1)), + number: 0, + total_difficulty: U256::from(0), + location: BlockLocation::Branch, + }; + + assert_eq!(ImportRoute::from(info), ImportRoute::none()); + } + + #[test] + fn import_route_canon_chain() { + let info = BlockInfo { + hash: H256::from(U256::from(1)), + number: 0, + total_difficulty: U256::from(0), + location: BlockLocation::CanonChain, + }; + + assert_eq!(ImportRoute::from(info), ImportRoute { + retracted: vec![], + enacted: vec![H256::from(U256::from(1))], + }); + } + + #[test] + fn import_route_branch_becoming_canon_chain() { + let info = BlockInfo { + hash: H256::from(U256::from(2)), + number: 0, + total_difficulty: U256::from(0), + location: BlockLocation::BranchBecomingCanonChain { + ancestor: H256::from(U256::from(0)), + enacted: vec![H256::from(U256::from(1))], + retracted: vec![H256::from(U256::from(3)), H256::from(U256::from(4))], + } + }; + + assert_eq!(ImportRoute::from(info), ImportRoute { + retracted: vec![H256::from(U256::from(3)), H256::from(U256::from(4))], + enacted: vec![H256::from(U256::from(1)), H256::from(U256::from(2))], + }); + } +} diff --git a/ethcore/src/blockchain/mod.rs b/ethcore/src/blockchain/mod.rs new file mode 100644 index 000000000..29a4ee684 --- /dev/null +++ b/ethcore/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 database. + +pub mod blockchain; +mod best_block; +mod block_info; +mod bloom_indexer; +mod cache; +mod tree_route; +mod update; +mod import_route; +#[cfg(test)] +mod generator; + +pub use self::blockchain::{BlockProvider, BlockChain, BlockChainConfig}; +pub use self::cache::CacheSize; +pub use self::tree_route::TreeRoute; +pub use self::import_route::ImportRoute; diff --git a/ethcore/src/blockchain/tree_route.rs b/ethcore/src/blockchain/tree_route.rs new file mode 100644 index 000000000..3c4906449 --- /dev/null +++ b/ethcore/src/blockchain/tree_route.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 . + +use util::numbers::H256; + +/// Represents a tree route between `from` block and `to` block: +#[derive(Debug)] +pub struct TreeRoute { + /// A vector of hashes of all blocks, ordered from `from` to `to`. + pub blocks: Vec, + /// Best common ancestor of these blocks. + pub ancestor: H256, + /// An index where best common ancestor would be. + pub index: usize, +} + diff --git a/ethcore/src/blockchain/update.rs b/ethcore/src/blockchain/update.rs new file mode 100644 index 000000000..6be2647d3 --- /dev/null +++ b/ethcore/src/blockchain/update.rs @@ -0,0 +1,21 @@ +use std::collections::HashMap; +use util::numbers::H256; +use header::BlockNumber; +use blockchain::block_info::BlockInfo; +use extras::{BlockDetails, BlockReceipts, TransactionAddress, BlocksBlooms}; + +/// Block extras update info. +pub struct ExtrasUpdate { + /// Block info. + pub info: BlockInfo, + /// Modified block hashes. + pub block_hashes: HashMap, + /// Modified block details. + pub block_details: HashMap, + /// Modified block receipts. + pub block_receipts: HashMap, + /// Modified transaction addresses. + pub transactions_addresses: HashMap, + /// Modified blocks blooms. + pub blocks_blooms: HashMap, +} 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/chainfilter/bloomindex.rs b/ethcore/src/chainfilter/bloomindex.rs new file mode 100644 index 000000000..22785495e --- /dev/null +++ b/ethcore/src/chainfilter/bloomindex.rs @@ -0,0 +1,40 @@ +// 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 . + +//! Represents bloom index in cache + +/// Represents bloom index in cache +/// +/// On cache level 0, every block bloom is represented by different index. +/// On higher cache levels, multiple block blooms are represented by one +/// index. Their `BloomIndex` can be created from block number and given level. +#[derive(Eq, PartialEq, Hash, Clone, Debug)] +pub struct BloomIndex { + /// Bloom level + pub level: u8, + /// Filter Index + pub index: usize, +} + +impl BloomIndex { + /// Default constructor for `BloomIndex` + pub fn new(level: u8, index: usize) -> BloomIndex { + BloomIndex { + level: level, + index: index, + } + } +} diff --git a/ethcore/src/chainfilter/blooms.txt b/ethcore/src/chainfilter/blooms.txt new file mode 100644 index 000000000..204186ec3 --- /dev/null +++ b/ethcore/src/chainfilter/blooms.txt @@ -0,0 +1,739 @@ +300054 0x00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +300059 0x00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000 +300221 0x00000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000008000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +301826 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +303166 0x00000000000000000000000000000000000000001000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000808000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000020000000001000000000000000000000000000000000000000000000000000000000000000000 +303345 0x00000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000008000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +303379 0x00000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000800000000000000001000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000080000000006000008000000000000000000080000000000000000000000000000000000000000001000000000000000000000008000000000400000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000800000000000000000000000000000000000002004000000000000 +303388 0x00000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000800000040000000001000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000080000000006001008000000000000008000080000000000000000000000000000000000000000001000000000000000000000008000000000400000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000800000000000000040000000000000000000002004000000000000 +303621 0x00000000000000000000008000000000200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000080000000000000000000000080000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000 +303670 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000400200000000000000 +303674 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000001000000000000200000000000000 +303683 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000400200000000000000 +303689 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000000400000000000000000000000000000000000000000000000000000000001000000000040200000000000000 +303692 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000400000000000000000000000000000000000000000000000000000000001000000000040200000000000000 +303716 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000001000000000000200000000000000 +303717 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000001000000000000200000000000000 +303748 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000400200000000000000 +303756 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000000400000000000000000000000000000000000000000000000000000000001000000000040200000000000000 +303758 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000400000000000000000000000000000000000000000000000000000000001000000000040200000000000000 +304090 0x00000000000000000000000000000000100000000000000000000000000000000000000000000000000200000000000000800000000000000000000000040000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000003000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000 +304095 0x04000000000000000000000000000000100000000000000000000000000000000000000000000000000200000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000 +304107 0x00000000000000000000000000000000100000000000000000000000000000000000000000000000000200000000000000800000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008800000000000000000400000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304113 0x00000000000000000000000000000000100000000000000000000000000000000000000000000000000200000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000002000000000000000000000000000000000000000000000000003008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304222 0x00000000000000000000000000000000100000000000000000000000000000000000000000000000000200000000000000800000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000800000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304245 0x00000000000000000000000000000000100000000000000000000000000000000000000000000000000200000000000000800000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000080000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304247 0x000000080000000000000000000000800000020000000000000000000000000000000000000000000202000000000000008000004004000000000000000000000000000000000000000000000200000000200000000080000000000000000000000004000000000000000000000000000000001040000000000000000000000000000004000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000c0002000000000000000000000000000000001000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304312 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000040000000000000200000000000000000000000000000000000000000000000000000000000000000000000000 +304319 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000100000000000020000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000080000000000000000000000000008000000000000000000000000000000000008000000000000000000000000000000000000020000000000002000000000000000000040000000000000200000000000000000000000000000000000000000000000000000000000000000000000000 +304367 0x00000000000000000000001000000000000000000400020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000100000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304375 0x00000000004000000000001000000000000000000400020000000800000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000020000000000000000000000000000000000000000000000000008000000000000010000000008000000000000000000000000000000000008000800000000000000000000000100000000000000000000000000000000000000000100000000000000002000000000002000000040010010000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304407 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304431 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +304433 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +304608 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000400000000000000000000040000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000 +304609 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000400000000000000000000040000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000 +304788 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +304794 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +304819 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +304835 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304849 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +304856 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304862 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +304872 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +304881 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +304902 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +304996 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +304999 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305006 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +305010 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305425 0x00000000004000000000000000000001000000000000020000000000000000000000000000000000000000000000000000000000008000000080000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010400000048000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000400000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305445 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000080000100000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305448 0x00000000004000000000000000000000000000000000020000000000000000000004000008000000000000000000000000000000000000000000000000000800000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000080000100000000002000000000000000000040000000000000000000000100000000000000000000000000000000000000000000000000000000000000000 +305450 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000080000000000000000000000000000020000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000004000000000000000000000000000 +305452 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000002000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000080000000000000000000000000000020000000000000000000000000000000000000000000008002000000000000000000040000000000000000000000000400000000000000000000000000000000004000000000000000000000000000 +305454 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000001000000040000000000000000000000000000000000000000000000000000000000000000000000000840000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305457 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305463 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000200080000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305464 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000008000000000000000000000000000000000240000000200480000000000000000000000000000000000000000000000000000002000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305468 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008080000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000008800000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305488 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000002000000000000008000000000000010000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305492 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000008000000000000000000000000000000008040000000000000000000000000000002000000000001000000000000000000000000000400000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000200000000000000000000000000000000000000000000 +305501 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000008000000000000000000040000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000080000000000000 +305502 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000008000000000000008000000000000000000040000000001000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000080000000000000000000000000000000000010000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000080000000000000 +305510 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000044000004000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305616 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305620 0x0000000000400000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000040000000000000080000000000000000000000000000800000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000040000000001000000000a000000000000000010000000000000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305622 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000080000000000000000000000000200000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000080000000000000 +305624 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000001000000000000000080000000000000000000000000200000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000004000000000000000000000000004000000000000000000000000000000000000080000000000000 +305626 0x00000000004000000000100000000000000000000000020000000000000000000000000002000000000000000000000000000000200000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000004000000000002000000000000002000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305627 0x00000001000000000000000000000200000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305629 0x00000001004000000000000000000200000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000040000000000000000001040000000000000000000000000000000000000000000000000000000000000000000 +305634 0x00000000005080000000000000000000000000000000020000400000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008020000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000400000000000000000000000 +305826 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000400000000000000002000000000000000000840000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305827 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000100000000000000000000000000040000000000000000000000000000000000000000000000000000000000000040000000000000000000000010000000008000000000000000000000000000000100008000000000000000000000000000000000000000000000000000000000000000000000400000000000000002004000000000000000840000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305829 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000008000000000080000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000080000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305834 0x00000000004002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000041000000000000000000000000000000000000008000000000080000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000020000000000000000000000000000008000000000000000000000000000000000000000000000080000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +305839 0x00000000000000000000000000000000000010000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000080000000000000000000000000000000000000000000000000000000000000 +305841 0x40000000004000000000000000000000000010000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000008000000008000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000080000000000000000000000000000000000000000000008000000000000000 +306889 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +307290 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +307508 0x00000000000000000000000000000000000000000000020000000000000000000000200000000000400000000000000000000000000000000000000000000000002000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +307509 0x00000000004000000000000000000000000000000000020000000000000000000000200000000000400000000000000000000000000000000000000000000000002000000000000000008000000000000000000000000000000000040000000000040000000000000000000000000000000000000000000000000000000000000000000000000010000000008000010000004000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +307513 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000004000000000000000000000000010000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000200000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +307519 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000001000000000000002000000000000000000040000000000000000000000000000000000000000000080000000000000000000000000000000000000000000 +307528 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000020000000000000000000000000000000000000000000000000000000000000000100000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +308010 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000080000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000 +308115 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000001000000000000200000000000000 +308124 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000400200000000000000 +308127 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000001000000000000200000000000000 +308157 0x00000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000020000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000 +308183 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000002020000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +308190 0x00000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000020000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000 +308216 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000002020000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000 +308224 0x00000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000020000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000 +308257 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +308265 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +308267 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +308268 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +308285 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +308599 0x00000000000000000000000000000000000000000000080000000000000800000000000000000010000000000000000000200002000000000000000000000000000000000000000000020000001000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004010010000002000000000000000400000000000000000000000000000000000000000000040000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +309175 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +309177 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +309184 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +309186 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +309190 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +309194 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +309198 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +309417 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +309881 0x00400000000000000000000000000000000000000000004000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000 +309883 0x00400000000000000000000000000000000000000000004000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000 +309892 0x00400000000000000000000000000000000000000000004000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000 +310069 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +310114 0x00400000000000000000000000000000000000000000004000000000000000000000000000100000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +310116 0x00400000000000000000000000000000000000000000004000000000000000000000000000100000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +310177 0x00400000000000000000000000000000000000000000004000000000000000000000000000100000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +310533 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +310589 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +310592 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +310599 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +310601 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +310604 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +311317 0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +311758 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +311858 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +311859 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +311865 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +311888 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +312096 0x00400000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000200000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +312124 0x00400000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000200000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +312367 0x00400000000000000000000000000000000400000000004000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +312371 0x00400000000000000000000000000000000400000000004000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +312383 0x00400000000000000000000000000000000400000000004000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +313355 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +313368 0x00000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +313507 0x00000000000000000000000000000000000000000200000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +313526 0x00000000000000000000000000000000000000000200000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +313724 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +313789 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +314190 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +314375 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000008000000000000000008000400000000000000000000000000 +315698 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +315705 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +315780 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +316726 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000040000000000000000 +316747 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +317179 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000001000000000000200000000000000 +317522 0x04000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000800000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000006001008000000000000008000080000000000000000000000000000000000000000001000000000100000000000008000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000040000000000000008000002004000000000000 +317526 0x00000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +317536 0x00000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000020000000000800000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000006000008000000000000000000080000000000000000000000000000000000000000001000000000000000000000008000000800400000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000002004000000000000 +317567 0x00000000000000200000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000001004000000000000000004000000020000000000000000000000000000000000000000000000000000000000000000000000000000000001000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +317588 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +317597 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +317606 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +317610 0x00000000000000200000000000000000000000000000000000020000000000000000000000000000000000400000000000000000000800000080000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000001044000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000400000000000000000000000000000000000000000000000000000000000000000000440000000000000000 +317643 0x00000000000000200000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000010000000000000000000000000000004000000000020000000000000000000000000000000000000000000001004000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +317646 0x00000000000000000000000000000000000000000000000000004000000000000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000010000000000000000000000000000004000000000020000000000000000000000000000000000000000000001000000000000000000004000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +317660 0x00000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000800000000000000001000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000080000000006000008000000000000000000080000000000000000000000000000000000000000001000000000000000000000008000000000400002000000000000000000000000000000000000000000000000000008000000000000000000000000000000000800000000000000000000000000000000000002004000000000000 +317957 0x00000000000000000000000000000000000000000200000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +318030 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +318032 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +318033 0x00000000001000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000000000000000800000000000000001000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000004000000000000000080000000006000000000000000000000000080000000000000000000000000000000000000000005000000000000000000000000000000008400000000000000000000000000000000000000000000000000008000000000000000000000000020000000000000800000000000000000000000000000000000002004000000000000 +318034 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +318036 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +318063 0x00000000001000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000000000000000800000040000000001000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000080000000006000000000000000000000000080000000000000000000000000000000000000000005000000000000000000000000000000008400000000000000000000000000000000000000000000000000008000000000000000000000000040000000000000800000000000000000000000000000000000002004000000000000 +318074 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000100000010020000000000000000000200000000000000000080000000020000000000000000000800000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000008000000000000000000000000000000000000000000000000000008000000000000000000000000020000000000000000000000000000000000000000000000000102000000000000000 +318096 0x04000000001000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000000000000000800000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000080000000006000000000000000000000000080000000000000000000000000000000000000000005000000000100000000000000000000008400000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000800000000000000000000000000000008000002004000000000000 +318137 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +318528 0x00000000001000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000020000000000800000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000080000000006000000000000000000000000080000000000000000000000000000000000000000005000000000000000000000000000000808400000000000000400000000000000000000000000000000000008000000000000000000000000000000000000000800000000000000000000000000000000000002004000000000000 +318627 0x00000000001000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000000000000000800000000000000001000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000004000000000000000080000000006000000000000000000000000080000000000000000000000000000000000000000005000000000000000000000000000000008400002000000000000000000000000000000000000000000000008000008000000000000000000000000000000000800000000000000000000000000000000000002004000000000000 +318639 0x00000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000800000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000002000000000000000000000010000000000000004800000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000080000000000000000000000000 +318650 0x00000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000800000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000010000000000000004000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000 +318653 0x00000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000004000000000000000000000000080000000000000000000000000000000000000000000000000000000200000000000000000000000000800000000000000000000000000000000000000000000000000000000000010000000000000000000000000800000000000000000000000000000000000000000000000000000 +318904 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +319523 0x00000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000400000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +321346 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +321884 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +321900 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000040000000000000000 +322038 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +322041 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +322043 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +322047 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +322048 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +322056 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +322059 0x00000000001000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000000000000000800000000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000080000000006000000000000000000000001080000800000000000000000000000000000000000005000000000000000000000000000000008400000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000800000000000000000000000000000000000002004000000000000 +322083 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +322090 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +322108 0x04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000010020000000000000000000200000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000080000000000000000000000000000000000000000004000000000100000000000000000000008000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000800000000000000000000000000000008000100000000000000000 +322121 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000010000000000100000010020000000000000000000200000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000001080000800000000000000000000000000000000000004000000000000000000000000000000808000000000000000400000000000000000000000000000000000008000000000000000000000000000000000000000800000000000000000000000000000000000100000000000000000 +322122 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000100000010020000000000000000040200000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000080000000000000000000000000000000000000000004000000000000000000000000000000008000000000000000000000000000000000000000000000000000008000000000000000000000000040000000000000800000000000000000000000000000000000100000000000000000 +322128 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000010020000000000000000000200000000000000000088000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000080000000000000000000000000000000000000000004000000000000000000000000000000008000002000000000000000000000000000000000000000000000008000008000000000000000000000000000000000800000000000000000000000000000000000100000000000000000 +322454 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008010000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000010000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000080000000000000000000000000000000000000000000000000000000000000000000000000 +322509 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008010000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000080000000000000000000000000000008000000000200000000000000000010000000000000000000000000000000000000000000000000000000002000000000200000000040000000000000080000000000000000000000000000000000000000000000000000000000000000000000000 +322550 0x00000000000000000000000000000000000000000200000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +322749 0x00000000001000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000000400000000800000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000080000000006400000000000000000000000080000000000000000000000000000000000000000005000000000000000000000000000000008400000000080000000000000000000000000000000000000000008000000000000000000000000000000000000000800000000000000000000000000000000000002004000000000000 +322750 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000080000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000020000000000000040000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +322752 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000008000000000000000000080000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000080000020000000000000040000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000080000000000000000000000 +322758 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +322760 0x00000004004000000000000000000000000000000000020000000000000000000000100000000000000000000000000000000000000000000000000000000000010000000000000000008000000000000000000000000000000000040000000000002000000000000000000000000000000000000000000004000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +322764 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000001000000000000000000000000000000000000000000000000000000000000001000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000020000000000000000000000000000000 +322765 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000001000000000000000000000000000000000000000000000000000000000000001000000000000000002000000000200000000040000000000000000000000000000000000000000000000000000000020000000000000000000000000000000 +322767 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002080000000000000000040000000000000000000000000000000000000000000002000000000000000000000000000000000000000000 +322768 0x00000000004000000000000000000000000000000000120000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000400000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002080004000000000000040000000000000000000000000000000000000000000002000000000000000000000000000000000000000000 +322774 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000008000000000000000000000000000000000000000000000000000000000000000000002001000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +322776 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000010000000000000000000000000040000000000000000000000000000000010000000008000000000000000000000000000000000009000000000000000008000000000000000000000000000000000000000000000000000000000000000000002001000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +322777 0x00000000004000000000008000100000000000000000020000000000000002000000000000000000000000000000000000000004000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000020000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000001000000000000000000000000000000000000000000000000 +324029 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +324316 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000004000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +324318 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000 +324322 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000400000000000000000000000000000000000000000000000000000008000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +325807 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +326760 0x00000000000000000000000000000000000000000000000000000040000000000000001000000000000000000000000000008000000000000000000000000000000000008000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000002000000000000008000000000000000 +327103 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +327105 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +327227 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000040000000000000000 +327399 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +327544 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +327690 0x00000000000000000000000000000100000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +328002 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000200000000000 +328269 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +328529 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +328585 0x20000000000000000000100000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +328870 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +329480 0x00000000000000000000000000000000000000000000020000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000200000000000000000000000020000000000000000000000000000000000000000000 +329484 0x00000000004000000000000008000000000000000000020000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000040000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000200000000000000000000000020000000000000000000000000000000000000000000 +329485 0x00000000000000000000000000000000001000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +329491 0x00000000000000000000000000000000001000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +329513 0x00000000000000000000000000000000001000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +329519 0x00000000000000000000000000000000001000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +329659 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000020000000000000000000000000000000000000000000000000000000000020000000010000000008000000000000000000000000000000000008000000400000000000000000000000000000000000000000000000000000000000000000000000000000002000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000020000000 +329667 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000100000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000002000000000000000000000000000000000000000000 +329668 0x0000000000400000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000004000000000000010000000000000000000000000000000000000000000000000001000000000000000000001000000000c000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000002000000000000000000800000000000000000000000 +329673 0x00000000004000001000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000004000000000000000000000000000000000000000000000000004000000000000000000010000000008000000000000000000000000000002000008000000000000000000000000000000000000000000000000000000000000000000000400400000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +329740 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000010000000000000 +329749 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000008000000000000000000000000000000000000000002000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +329750 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000008000000000000000000000000000000000040000000040000000000000000000000010000000000000000000000000000000000000000000000000000010000000008000000000000000000000080000000000008000000000000000000000000000000000000000002000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000400000000000000000000000000000000000000000000 +329824 0x00000000000000000000000000000000000000000000200000000000000000000000001000000000000000000000000000008000000008000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +329964 0x00000000000000000000000000000000000000000000000000000000100000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +330023 0x00000000000000000000000000000000000000000000000000000000100000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +330207 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000004000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000200000000000000000000000008000000000000000 +330473 0x00000000000400000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000001000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +330511 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000002000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000040000000000000000 +330579 0x00000000000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000001000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +330683 0x00000000000000000000000000000000000000000000080000000000004000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +330919 0x00020000000000000000000000000000000000000000000000000000000000000008001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +331009 0x00000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +331542 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000100000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000004000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +332007 0x00000000000000000000000000000000000000000000000000000200000080000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008200000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +333256 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000400000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000010000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +333294 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +333583 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000200000000000000000000000000000000000000000000000000010008000000000000000 +333640 0x80000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000004000000008000000000000000000000000000000000000010000000000000000000000000000000000008000000000000000 +334263 0x00000000000000080000000000000000000000000000000000000000000000000100001000000000000010000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +334279 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000040000020000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000 +334883 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +334915 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000004000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +334919 0x00000020000000000000000000000000000000000000000000000000000000000000001000000000000020000000000000008000000000000000000000000000000000000020000000000000020000812000002000000000000000000000000001000000000000000000000000000000400000000000000000000000000000000000000000000000040000800000000010000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000008000400000000008000000000000000 +335076 0x00000000000000001000000000000000000000000000000000000000000000000000001000000000000000000100000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +335348 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000008000000000000000000000040000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000008000000000 +335643 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +335649 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +335652 0x00000000000008000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +335684 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000002000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000 +336089 0x0000000000000000000000000000000000000000000000000000000000020000000000100000000000000000000000000000800000000000000000000000000000000000000000000000000000000080200000a000000000000000000000000001000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +336231 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336234 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336242 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336243 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336244 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336245 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336247 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336248 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336255 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336260 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336263 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336264 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336266 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336334 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336336 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336337 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336338 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336439 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336451 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336452 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336453 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336461 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336495 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336497 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336507 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336508 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336509 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336510 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336518 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336520 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336521 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336522 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336526 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336527 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336528 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +336543 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000040000000000000000000200000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000 +337012 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000001000000000000000000000000400000000000000802000002000000200000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +337642 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000408000000000000000000000000000000000040000080000000000000000080000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000020000000000000000002000000000000000000040000000000000001000000000000000000000000000000000000000000000000000000000000000000000000 +337647 0x00000000000000000000000000000000000000000000020000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000800000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +337649 0x00000000004000000000000000000000000000000000020000000000000080000000100000000000000000000000000000000000000000000000000000000000000000000000000000008002000000000000000000000000000000040000000000000000000000000000000800000000000000000000000000000000000000000000000002000010000000008000000000000000000000000000000000008000000000000000000000000000000000200000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +337653 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000040000000000000000000040000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +337654 0x00000000004000000000008000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000020000040000000000000000000040000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +337655 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000040000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000400000000040000000000000000000000000000000000000000000000000000000000000000000000 +337656 0x00000000004000000000000000000000000400000000020000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000008000040000000000000000000000000000040000000000000000000000000000000000000000000000000000004000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000400000000040000000000000000000000000000000000000000000000000000000000000000000000 +337663 0x00000000004000000000000000000000080000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000001000000000000000000000000000050000000000000000000000000040000000000000000000000000000000000000000004000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000080000000000000000000000000000000000000 +337664 0x00000000000000000000000000000000000000000000020000000010000000000000000000000000001000000000000000000000000000000000000000000000000200000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +337669 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000020000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000008000000000 +337672 0x40000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000020000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000020000000000000010000000008000000000000000000000000008000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000008000008000000000 +337731 0x00000000000000000000000020000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000800000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +338275 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010004000200000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +338281 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010004000200000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +338336 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +338424 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008004000000000000000000000000000000000000100000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +338435 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000008000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000004000000000000000000000000010000000000000000000000000000000000000 +338439 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000010802000002000000000000000000000000001000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000040000000000000000000000000000000000000000000000008000000000000000 +338661 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +338991 0x00000000000000000000000000200000000000000008000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000400800000000000000000000000000000010000000000000000000000000000000000000000000000000 +339173 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002400000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +339369 0x00000020000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +339427 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000020000000000000000000001000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +340633 0x00000000000000000000000000000000000000000000020000000004000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000008000000000000001000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +340635 0x00000000004000000000000000000000000000000000020000000004000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000008000000000000001000000000000200000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000001000000000200000000000000000000000000000000000000000000000000000000000000000000 +340653 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000001000000002000000000000000000040000000000000000000000000000000000000000000000000000000010000000000000000000000000000000 +340658 0x0000000000400000000000000000000400000000000002000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000001000000000800000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000100000000a000000000000000000040000000000000000000000000000000000000000000000000000000010000000000000000000000000000000 +340674 0x00000000000800000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000100000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040080000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +340675 0x00000000004800000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000100000000000000000000000000000000000000000000000000000000000000000000000000000002000010000000000000040080000000000000000000000000000000000002000000000000000000080000000000000000000000000000 +340685 0x00000000000000000000000000000000000000000000020010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000008000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +340686 0x00004000004000000000000000000000000000000000820010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000010000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000008000000000000040000000000000000000000000000000000000000000000000002000000000000000000000000000000000000 +340700 0x00000000004000000000000000000000000000000000020001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000080000000000000000000000000000000000008000000000000000000000000000000000000000000002004200000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000001000 +340708 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000008000000000000000000000000000040000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000080000000000000000000000000000000000000 +340710 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000008000000000000000000000000000040000000000000100000000000000000800000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000400000000000000000000000000000000000000000000000000002000002000000000000040000000000000000000000000000000000000000000000000080000000000000000000000000000000000000 +340712 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000080040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000008000000000200000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +340713 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000080840000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000028000000100000000000000000000000000008000000000200000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000001000000000000000000000 +340718 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000100000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000002000000000000 +340719 0x00000000004000000000000000000000000000000000020000000040000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000008000000000000080000002000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000100000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000002000000000000 +340727 0x00000000004000000000040000002000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000200000000000080000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000002000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000001000000000000000000000000000000 +340728 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000002000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000100000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +340835 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +340988 0x00000000000000000010000000000000000000000010000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000010000000000008000000000000000 +341695 0x00000000000000000000000010000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000001000000000000000000000000000000000000000000000000000000000008000000000000000 +341985 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000100000000000004000000000000001000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +341997 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000104000000000004000000000000001000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +342001 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000100000000000004000000000000001000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +342004 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000100000000000004000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +342007 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000004000000000000001000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +342008 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000004000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +342026 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000002000000004000000000000000000000000000000000000000000000000000000001000000000000000000004000000020000080000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +342027 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +342033 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +342035 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +342036 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +342041 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 +342047 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000100000000000000000000000000000000002000000104000000000044100000000000001000002000000000000000000000001000000000000000000004000000000000080000000000000000000000000000000000000002000000000000000000000000020000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +342053 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +342080 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000400000002000000000000000000000000000000000000000000040000000000000000000001040000000000000000000000000000000080000000010000000000000000000000000000000000000000000000000000000020000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000440000000000000000 +342101 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 +342107 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +342111 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +342115 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 +342118 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000400000002000000004000000000000000000000000000000000000000000000000000000001000000000000000000004000000000000080000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +342125 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +342140 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 +342141 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +342145 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000400000002000000000000000000000000000000000000000000040000000000000000000001040000000000000000000000000000000080000000010000000000000000000000000000000000000000000000000000000020000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000440000000000000000 +342162 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +342173 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +342188 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +342272 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000400000000000000000 +342386 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000008000000000000000000000000000000000000000000000000000004000000000000000000000000000008000000000000000000000000001000000000000000000004000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000010000000004000000000000000000000000010000000000000000000400000000000000000 +342399 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000 +342466 0x00000000000000000000000000000000000000000000000000002000000000000000001000000000080000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +342601 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +342616 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 +342618 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 +342924 0x00000000000000000000000000000000000010000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +342964 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000081000000000000000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +343006 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000080000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000 +343021 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000004000000000000000000000000000000000000000000000000080000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000 +343059 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000008000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +343079 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000200000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +343083 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000040000000000000802000002000000000000000000000000001000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +343133 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +343162 0x00000020000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000100000000000000000000000000008000400000000000000000000000000 +343185 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000008000400000000000000000000000000 +343339 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000080000000000000000802000002000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +343946 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +343966 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +343971 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +344121 0x00000000000000000000000000000000000000000000000000000040000000000000001000000000000000000000000000008000000000000000000000000000000000008000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000002000000000000008000000000000000 +344164 0x00000000000000000000000000000000000000000000000000000040000000000000001000000000000000000000000000008000000000000000000000000000000000008000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000002000000000000008000000000000000 +344839 0x00000000000000000000000000000000000000000000000000000000000000000200001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000008000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +345506 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +346112 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +346392 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +346395 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +346398 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +346425 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +346448 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +346451 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +346454 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +346464 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +346466 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +347014 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000400000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +347301 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000200000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000002000000000000000000000000000000000000000000000000000000000000000008000000000000000 +347333 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000200000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000002000000000000000000000000000000000000000000000000000000000000000008000000000000000 +347613 0x00000000000000000000000000000000000000000800000000000000000000000000000000000000000001000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010004000000002000000000000000000000000000000000000000000000000000000001000000040000000000000000000000800000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000001000000000000000000000 +347700 0x00000000000000000000000000000000000000000000000000000000002000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400010000000000000 +347705 0x00000000000000000000000000000000000000000000000000000000002000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400010000000000000 +347711 0x00000000000000000000000000000000000000004000000000020000002000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040010000000000000 +347853 0x00000000000000000000000000000000000000000000000000000000002000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000 +347953 0x00000000000000000000000000000000000000000000000000000000002000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000 +347958 0x00000000000000000000000000000000000000004000000000020000002000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040010000000000000 +347960 0x00000000000000000000000000000000000000000000000000020000002000000001000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040010000000000000 +348019 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +348244 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000004000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +348443 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000400000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +348675 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000080000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000400100000000000000000000000000000000000000000000000008000000000000000 +348743 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +348936 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000100000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000002000000000000000000000000000000000000000008000000000000000 +350544 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +351473 0x00000000000000000000000000000000000000000000000000000000002000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000 +353157 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +353181 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000400000000000000000 +353196 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000080000000000000000000000000000000000000040000000000000000 +353273 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000 +353276 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000080000000000000000000000000000000000000040000000000000000 +353359 0x00000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000200000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000100000040 +353360 0x00000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000040 +353361 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008002400000000000000000000000000 +353367 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000080000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000008000000000000000 +353370 0x02000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +353438 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000080000000000000000000000000000000000000000000000000002000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000040 +353443 0x0000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000a000400000000000000000000000000 +353447 0x00000028000000000000000000000080000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +353479 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000002000001000000000000000000000000100000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +354071 0x02000000000000000000000000000000000000000000020000000000000000000000000040000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000001000000000020000000000000000000000200000000000000020000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000 +354151 0x00000000000000000000000000000000000000000000002000000000000000000000400000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004040000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000080000000400000000000000000000000000000000000000000000000000000000000000000000000000000 +354162 0x00000000000000000000000000004000000000000000000000000000000000000000410000000000200000000000000002000000000002000000000040000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000 +354233 0x00000000000000000000000000000000000000000000000000000000000000000000400040000004000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024040000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000400000000000000000000000040000000000000000000000000000000000100000000000000000 +354585 0x00000000000000000000000000000000000000000000000000100000000000000000400000000000200000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004001000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000 +354866 0x00000000000000000000000000000000000000000000000000001000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000001 +356461 0x00000000000000000000000000200000000000000000000000000000010000000000000000000000000000000000000000202000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +356488 0x00000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000200000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000020000000000000080000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000 +356513 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000100001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000080000000000000a00000000000000000000000 +356526 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +356535 0x00000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000 +356543 0x00000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000800080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000 +357195 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +357579 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +357588 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +357590 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000200000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +357592 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +357600 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +357622 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +357630 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +358290 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000400000002000000004000000000000000000000000000000000000000000000000000000001000000000000000000004000000000000080000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +358426 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 +358556 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +358811 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000400000000000000000000000000000000002000000000008000000000000000 +359114 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +359375 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000100000000000000000 +359378 0x00000020000000000010000000000000000004000000000000000200400000000000000000000000000000000002000000000000000000020000000000000000000000000000000000000000000000010000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000040000000000040010000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000400000000000 +359538 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +361585 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +361588 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +361732 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000842000002000000000000000000000000001000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000080000000000000000000000000000000000000000000000000000008000000000000000 +361757 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +361775 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +362002 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000010000000000000000000000000802000002000000000000000000000400001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +365791 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000040 +365793 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000010000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000400010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +369141 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000200000000000000000000000000000000000000000000000000000000000000000008000000000010000 +369239 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +369249 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +369253 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +369259 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +369261 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +369263 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +369274 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +369426 0x00000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000200000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000100000040 +369428 0x20000020000000000000000000800000000004000000000000000200400000000000000040000000000000000000000000000000000000020000000000000000000000000000000000000000000000010000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000040000000000000010000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000008000400800000000000000000000000 +369431 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018000400000000000100000000000040 +369538 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000040 +369540 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000008000400000000000000000000000000 +370399 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000001000000000000802000002000000000000000000000000001000000100000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +370517 0x00000000000000000000000000000080200000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000080004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +370545 0x00000000000000000000000000000080200000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000080004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371190 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371280 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371286 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371288 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371299 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371307 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371327 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371329 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371352 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371360 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371362 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371369 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371378 0x00000000000000000000000000000080200000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000080004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371450 0x00000000000000000000000000000080200000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000080004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371489 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371509 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371532 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371658 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371660 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371876 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371904 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371906 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371912 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371914 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371918 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371931 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371933 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371938 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +371940 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +371973 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +372006 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +372014 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +372847 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +374209 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +374225 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +374365 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +374388 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020001000000000000000000000200000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +375079 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +375093 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +375401 0x00000000000000000000000000000000000400000400000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +375440 0x00000000000000000000000000000000000400000400000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +375447 0x00000000000000000000000000000000000400000400000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +376493 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +376573 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +376588 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +376644 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +376650 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +376668 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +376906 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +377026 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +377139 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000001000000000000080000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000080000000000000000000000000000000000000040000000000000000 +377506 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +377523 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +377525 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +377581 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000040 +377586 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000040000000000000000000000100000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +377608 0x00000000000000000000000000000000000000000200000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +377627 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000080000000000000000000000000000000000000040000000000000000 +377629 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000080000000000000000000000000000000000000040000000000000000 +377703 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000001000000000000080000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000080000000000000000000000000000000000000040000000000000000 +377730 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +377746 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000400000000000000000 +377877 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000400000002000000004000000000000000000000000000000000000000000000000000000001000000000000000000004000000000000080000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +377894 0x00000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +377905 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000400000002000000004000000000000000000000000000000000000000000000000000000001000000000000000000004000000000000080000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +377917 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +377922 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000040000000000000000 +377925 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +378345 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +378347 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +379027 0x00000020000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +379032 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +379039 0x08000020000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +379158 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000400000000000000000002000040000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +379161 0x00000400004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000040000000000000000000000000000000000000000000010000000008000000000000000000000000000000020008000000000000000000000000000000000000000000000000000000000000000000400000000000000000002000040000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +379163 0x00000000000000000000000000000000000000000000020000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000008000010000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000080000000000000000000000000000000000000000 +379164 0x00000000004000000000000000000000000000100000020000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000008000010000000000000000000000000000040000000000001000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000100000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000080000000000000000000000000000000000000000 +379167 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000004 +379170 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +379171 0x00000000004000000000000000800000000000000000020000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000008000000000000000000000000000002000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000004 +379172 0x00000000000000000010000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000200000000000000000000000000000000000000000000000000000000000000000000000 +379176 0x00000000004000000010000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000100000000000000000000000000000000000000000200000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000040000000000000000000000000000000002000000000000000000040000000000000000200000000000000000000000000000000000001000000000000000000000000000000000 +379180 0x00000000000080000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000800000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +379182 0x00000000004080000000000002000000000000000800020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000800000000000000000000050000000008000000000000000000000000800000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +379210 0x00000000000000040000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000004000000000000000000000400000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +379212 0x00000000004000040000000000000000000000000000020000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000200000000000008000000000000000000000000000000000000000004000000000000000000000400000000000000000000002000000000000000000040002000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +379214 0x00000001000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +379216 0x00000001004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000008000000000000008000000000000000000000000000000000040000000000000000000000000000000000020000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000020002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +379217 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000800000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000020000000000000000000000000000000000000000000000000000000000000000 +379219 0x00000000004000000000000000000000000000000000020000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000008000000000000000000000000010000000000000000010000000008800000000000000000000000000000000008000020000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000020000000000000000000000000000000000000000000000000000000000000000 +379220 0x00000000000000000000000000200000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000100000000000100002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +379224 0x00000000004000000000000000200000000000000000020000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000008000000000000000040000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000008000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000100000000000100002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000400000000000000 +379235 0x00000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000080000000000000000000000000000000000000000800000000000000000000000000000 +379237 0x00000000004000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000100000000008000000000000000000000000000000000000010000000008008000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000080000000000000040000000000000000080000000000000000000000000000000000000000800000000000000000000000000000 +381271 0x00000000000000000000000000000080000080004000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000200000000000004000000000000000000000000002000000000000000000400000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +381276 0x00000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +381689 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +382200 0x00000020000000000000000008000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +382217 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000400000010000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +382644 0x00000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000200000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000002000000000000000000000000000000000000000000000000000000000000000008000000000000000 +383284 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +383337 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +383354 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +383361 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +383427 0x00000000000000000000000000000000000004000800000000000000000000000000000000000000000001000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000800000001000000000008000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000040000000000000000000 +383466 0x00000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +383469 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000001000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +383515 0x00000000000000000000000000000000000004000800000000000000000000000000000000000000000001000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000800000001000000000008000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000040000000000000000000 +383519 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000010000000800000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000002000000000000000000000000000 +383630 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000400000000000000000 +383760 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +383802 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000080000000000400000000000000000 +383815 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000000001000000000000000000004000000000000000000000010000000000000000000000040000000000000000000000000000000020000000100000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +383844 0x00000000000000000000000000000000100000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +383852 0x00000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000002000000000000000000000000000400000000000000004000000000000000080000000000000000000000000000000000000001000000000000000000004000000000000000000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +383859 0x00000000000000000000000000000000000000804000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000002000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +383864 0x00000000000000000000000000000000000000800000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000080000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +383968 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000001000000000000080000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000080000000000000000000000000000000000000040000000000000000 +383973 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 +384127 0x00000000000000000000000000000000000004000800000000000000000000000000000000000000000001000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000800000001000000000008000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000040000000000000000000 +384138 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +384149 0x00000000000000000000000000000000100000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +384173 0x00000000000000000000000000000000100000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000400000000000000000000080000000000000000000000000000000000008000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000001000000000000000000005000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000800000000000000000000000000000400000000000000000 +384301 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000040000000000000000000000000000000000000000400000000000000000 +384422 0x00000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000400000000000000000 +384506 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +384511 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000400000000000000000 +384546 0x00000000000000000000000000000000000004000800000000000000000000000000000000000000000001000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000800000001000000000008000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000040000000000000000000 +384771 0x00001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000800000 +384825 0x00001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000 +384861 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000100000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +384917 0x00000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000400000000000000000 +384923 0x00002000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000001000000 +384965 0x00000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +385067 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000008000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000400000000000000000 +385073 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000008000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000400000000000000000 +385356 0x00002000000000000000000000000000000000010000000000000000000000000000000400000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000004000000000000000000000000000000004000000000000000000000000000000000000000000000000000000001000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000001000000 +386571 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +386620 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000 +386736 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000040000000000000000000000000000010000000020000000000000000000000000000000000000000000000000000000000000000010 +386786 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000280000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000040000000000000000000000000000010000000040000000000000000000000000000000000000000000000000000000000000000010 +386795 0x04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000040000000000000000000000000000000000040000000000000000000000000000010000000000000000000000000000000000000000000000000000008000000000000000000010 +386804 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000040000000000400000000000000000000000040000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000010 +386812 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000040000000000000000008000000000010000000000000000000000000000000000000000000000000000000000000000000000000010 +386818 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000800000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000040000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000010 +386899 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000080000000000000000000000000000040000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000010 +386939 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000002000000000000000000000000000000000000000200000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000010000000020000000000000000000000000000000000000000000000000000000000000000000 +386945 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000020000000000000000000800000000000000000000000000000000000000000200000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000 +386975 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000100000000000000000020000000000000000000000000000000000000000000000000000000000000000000 +387011 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000010000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000 +387014 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000001000000000000000000000040000000000000000000000000000000000000000000000040000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000 +387016 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000400000000800000000 +387032 0x04000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000 +387044 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000020000000000000000000000000000000000000000000080000000000000000000000 +387045 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000400000000800000000 +387206 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +387225 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +387241 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +387276 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000008000000000000000004000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000021000000000000000000004000000000000000000000400000000000000000000000000000000080000000000000000000000000000000000000040000000000001000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +387284 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000040000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +387365 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000440000000000000000 +387615 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000800008000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +387627 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000800000000000000000400000000000000000 +387641 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800008000000000000000000000001000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +387648 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000800008000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +387654 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000800008000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +387658 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000800008000000000000000000000001000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +387683 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000800008000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +387688 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000800008000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +387690 0x00000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000800008000000000000000000000001000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +387761 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000 +388108 0x00000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +388111 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000800000000 +388150 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000800000000 +388246 0x00000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000001000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000 +388285 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +388296 0x00000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000001000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000 +388516 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +388860 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000020000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000 +388893 0x00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000008000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000008000000000000000020000000000000000000010000000000001000000000000000000000000000000000000000000000000000000000000000400000000000000000 +388894 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000020000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000 +388907 0x00000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000104000000000004000000000000001000000000000000000000000000001000000000000000000004080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000004000000000000000400000000000000000 +388909 0x00000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000400000000000000000 +388912 0x00000000000000000000000000000000000000004000000000020000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000004000000000000000040000000000000000 +388918 0x00000000000000000000000000000000000000000000000000020000002000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000004000000000000000040000000000000000 +388923 0x00000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000008000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000001000000000000000000000080000000000000000000000000000000000000000000000000000000000008000000000000000020000000000000000000000000000000001000000000000000000000000000000000000000000000004000000000000000400000000000000000 +388940 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000020000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000 +388971 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000004000000000000000000000000000000000000000800000000000000000000000000000000000 +388990 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000 +389012 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000 +389158 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000 +389206 0x00000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000400000000000000000 +389238 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +389277 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000100000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000400000000000000000 +389292 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000800000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +389301 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000020000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +389309 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000020000000000000000000000000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +389324 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000008000000000000000000000000004000000000000000000000000004000000000000000000000000000000000000000000000000000000001000000000000800000024000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000440000000000000000 +389328 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +389343 0x00000000000000000000000000000000000000004000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000020000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000 +390001 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000001000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +390004 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000200000000000000000000000000000000000000020000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +390024 0x00000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +390042 0x00000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +390236 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +390306 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000001000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +390867 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +391685 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000010000000800000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000002000000000000000000000000000 +391690 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000010000000800000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000002000000000000000000000000000 +391691 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000010000000800000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000002000000000000000000000000000 +391697 0x00000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000040000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000 +391713 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000 +391849 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000100000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000400000000000000000 +392002 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000 +392097 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000020000000000000000000000000000000000000000000000000000000008000000000000000000080000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +392104 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000010000000000000000000000000000000000000000000000000000000020000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +392110 0x00000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000 +392294 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000004000000000000000000000000000000000000000000000000000000000 +392697 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000010000000000000000000000000000400000000000000000 +392960 0x00000000000000200000400000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +392970 0x00000000000000200000400000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +392990 0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +393302 0x00000010000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000400000000000000000 +393370 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +393752 0x00000000000000000000000000000000001000000000000000000000000000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000 +394354 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000800000024000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +394389 0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +394390 0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +394391 0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +394393 0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +394394 0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +394395 0x00000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000002000000000000000000000000000000100000000000000000100000000000000000000000000000000000000000000000000000000000002000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +394426 0x00000000000000200000400000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000200000000000000000000000000000000000000000000000000000000000000000000000008000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +394800 0x00000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000100000010000000000000000000000000000000000000000000000000000000000020000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000000000 +395595 0x00000000000000000000000000000000000000000000000000000000000100000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000800000000000000000000000000000000000000000000000000000000000000000008000000000000000 +395969 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +396348 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000010000000000000000000000000000400000000000000000 +397108 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000 +397588 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000 +397591 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000 +398412 0x00000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000008000000000000000000000000000000000000000000000000000000000802000002000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000008000000000000000000000000000000000000000000000000080000000000000000000800008000000000000000 +398456 0x00000020000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000 +398477 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +398679 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +398968 0x00000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020200000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000 +398972 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000400000000000000000 +399058 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000200000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000 +399804 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000010000000000000000000000000000400000000000000000 +399849 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000 diff --git a/ethcore/src/chainfilter/chainfilter.rs b/ethcore/src/chainfilter/chainfilter.rs new file mode 100644 index 000000000..387d750fd --- /dev/null +++ b/ethcore/src/chainfilter/chainfilter.rs @@ -0,0 +1,197 @@ +// 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 . + +//! Multilevel blockchain bloom filter. +//! +//! ```not_run +//! extern crate ethcore_util as util; +//! extern crate ethcore; +//! use std::str::FromStr; +//! use util::sha3::*; +//! use util::hash::*; +//! use ethcore::chainfilter::*; +//! +//! fn main() { +//! let (index_size, bloom_levels) = (16, 3); +//! let mut cache = MemoryCache::new(); +//! +//! let address = Address::from_str("ef2d6d194084c2de36e0dabfce45d046b37d1106").unwrap(); +//! +//! // borrow cache for reading inside the scope +//! let modified_blooms = { +//! let filter = ChainFilter::new(&cache, index_size, bloom_levels); +//! let block_number = 39; +//! let mut bloom = H2048::new(); +//! bloom.shift_bloomed(&address.sha3()); +//! filter.add_bloom(&bloom, block_number) +//! }; +//! +//! // number of updated blooms is equal number of levels +//! assert_eq!(modified_blooms.len(), bloom_levels as usize); +//! +//! // lets inserts modified blooms into the cache +//! cache.insert_blooms(modified_blooms); +//! +//! // borrow cache for another reading operations +//! { +//! let filter = ChainFilter::new(&cache, index_size, bloom_levels); +//! let blocks = filter.blocks_with_address(&address, 10, 40); +//! assert_eq!(blocks.len(), 1); +//! assert_eq!(blocks[0], 39); +//! } +//! } +//! ``` +//! +use std::collections::{HashMap}; +use util::hash::*; +use chainfilter::{BloomIndex, FilterDataSource}; +use chainfilter::indexer::Indexer; + +/// Should be used for search operations on blockchain. +pub struct ChainFilter<'a, D> + where D: FilterDataSource + 'a +{ + data_source: &'a D, + indexer: Indexer, +} + +impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource +{ + /// Creates new filter instance. + /// + /// Borrows `FilterDataSource` for reading. + pub fn new(data_source: &'a D, index_size: usize, levels: u8) -> Self { + ChainFilter { + data_source: data_source, + indexer: Indexer::new(index_size, levels) + } + } + + /// internal function which does bloom search recursively + fn blocks(&self, bloom: &H2048, from_block: usize, to_block: usize, level: u8, offset: usize) -> Option> { + let index = self.indexer.bloom_index(offset, level); + + match self.data_source.bloom_at_index(&index) { + None => return None, + Some(level_bloom) => match level { + // if we are on the lowest level + 0 => return match offset <= to_block { + // take the value if its smaller than to_block + true if level_bloom.contains(bloom) => Some(vec![offset]), + // return None if it is is equal to to_block + _ => None + }, + // return None if current level doesnt contain given bloom + _ if !level_bloom.contains(bloom) => return None, + // continue processing && go down + _ => () + } + }; + + let level_size = self.indexer.level_size(level - 1); + let from_index = self.indexer.bloom_index(from_block, level - 1); + let to_index = self.indexer.bloom_index(to_block, level - 1); + let res: Vec = self.indexer.lower_level_bloom_indexes(&index).into_iter() + // chose only blooms in range + .filter(|li| li.index >= from_index.index && li.index <= to_index.index) + // map them to offsets + .map(|li| li.index * level_size) + // get all blocks that may contain our bloom + // filter existing ones + .filter_map(|off| self.blocks(bloom, from_block, to_block, level - 1, off)) + // flatten nested structures + .flat_map(|v| v) + .collect(); + Some(res) + } + + /// Adds new bloom to all filter levels + pub fn add_bloom(&self, bloom: &H2048, block_number: usize) -> HashMap { + let mut result: HashMap = HashMap::new(); + + for level in 0..self.indexer.levels() { + let bloom_index = self.indexer.bloom_index(block_number, level); + let new_bloom = match self.data_source.bloom_at_index(&bloom_index) { + Some(old_bloom) => old_bloom | bloom.clone(), + None => bloom.clone(), + }; + + result.insert(bloom_index, new_bloom); + } + + result + } + + /// Resets blooms at level 0 and forces rebuild on higher levels. + pub fn reset_chain_head(&self, blooms: &[H2048], block_number: usize, old_highest_block: usize) -> HashMap { + let mut result: HashMap = HashMap::new(); + + // insert all new blooms at level 0 + for (i, bloom) in blooms.iter().enumerate() { + result.insert(self.indexer.bloom_index(block_number + i, 0), bloom.clone()); + } + + // reset the rest of blooms + for reset_number in block_number + blooms.len()..(old_highest_block + 1) { + result.insert(self.indexer.bloom_index(reset_number, 0), H2048::new()); + } + + for level in 1..self.indexer.levels() { + for i in 0..blooms.len() { + + let index = self.indexer.bloom_index(block_number + i, level); + let new_bloom = { + // use new blooms before db blooms where necessary + let bloom_at = | index | { result.get(&index).cloned().or_else(|| self.data_source.bloom_at_index(&index)) }; + + self.indexer.lower_level_bloom_indexes(&index) + .into_iter() + // get blooms + // filter existing ones + .filter_map(bloom_at) + // BitOr all of them + .fold(H2048::new(), |acc, bloom| acc | bloom) + }; + + result.insert(index, new_bloom); + } + } + + result + } + + /// Returns numbers of blocks that may log bloom. + pub fn blocks_with_bloom(&self, bloom: &H2048, from_block: usize, to_block: usize) -> Vec { + let mut result = vec![]; + // lets start from highest level + let max_level = self.indexer.max_level(); + let level_size = self.indexer.level_size(max_level); + let from_index = self.indexer.bloom_index(from_block, max_level); + let to_index = self.indexer.bloom_index(to_block, max_level); + + for index in from_index.index..to_index.index + 1 { + // offset will be used to calculate where we are right now + let offset = level_size * index; + + // go doooown! + if let Some(blocks) = self.blocks(bloom, from_block, to_block, max_level, offset) { + result.extend(blocks); + } + } + + result + } +} diff --git a/ethcore/src/chainfilter/indexer.rs b/ethcore/src/chainfilter/indexer.rs new file mode 100644 index 000000000..524fab1a9 --- /dev/null +++ b/ethcore/src/chainfilter/indexer.rs @@ -0,0 +1,154 @@ +// 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 . + +//! Simplifies working with bloom indexes. + +use chainfilter::BloomIndex; + +/// Simplifies working with bloom indexes. +pub struct Indexer { + index_size: usize, + level_sizes: Vec, +} + +impl Indexer { + /// Creates new indexer. + pub fn new(index_size: usize, levels: u8) -> Self { + if levels == 0 { + panic!("Indexer requires at least 1 level."); + } + + let mut level_sizes = vec![1]; + level_sizes.extend_from_slice(&(1..).into_iter() + .scan(1, |acc, _| { + *acc = *acc * index_size; + Some(*acc) + }) + .take(levels as usize - 1) + .collect::>()); + + Indexer { + index_size: index_size, + level_sizes: level_sizes, + } + } + + /// unsafely get level size. + pub fn level_size(&self, level: u8) -> usize { + self.level_sizes[level as usize] + } + + /// Converts block number and level to `BloomIndex`. + pub fn bloom_index(&self, block_number: usize, level: u8) -> BloomIndex { + BloomIndex { + level: level, + index: block_number / self.level_size(level), + } + } + + /// Return bloom which are dependencies for given index. + /// + /// Bloom indexes are ordered from lowest to highest. + pub fn lower_level_bloom_indexes(&self, index: &BloomIndex) -> Vec { + // this is the lowest level + if index.level == 0 { + return vec![]; + } + + let new_level = index.level - 1; + let offset = self.index_size * index.index; + + (0..self.index_size).map(|i| BloomIndex::new(new_level, offset + i)).collect() + } + + /// Return number of levels. + pub fn levels(&self) -> u8 { + self.level_sizes.len() as u8 + } + + /// Returns max indexer level. + pub fn max_level(&self) -> u8 { + self.level_sizes.len() as u8 - 1 + } +} + +#[cfg(test)] +mod tests { + use chainfilter::BloomIndex; + use chainfilter::indexer::Indexer; + + #[test] + fn test_level_size() { + let indexer = Indexer::new(16, 3); + assert_eq!(indexer.level_size(0), 1); + assert_eq!(indexer.level_size(1), 16); + assert_eq!(indexer.level_size(2), 256); + } + + #[test] + fn test_bloom_index() { + let indexer = Indexer::new(16, 3); + + let bi0 = indexer.bloom_index(0, 0); + assert_eq!(bi0.level, 0); + assert_eq!(bi0.index, 0); + + let bi1 = indexer.bloom_index(1, 0); + assert_eq!(bi1.level, 0); + assert_eq!(bi1.index, 1); + + let bi2 = indexer.bloom_index(2, 0); + assert_eq!(bi2.level, 0); + assert_eq!(bi2.index, 2); + + let bi3 = indexer.bloom_index(3, 1); + assert_eq!(bi3.level, 1); + assert_eq!(bi3.index, 0); + + let bi4 = indexer.bloom_index(15, 1); + assert_eq!(bi4.level, 1); + assert_eq!(bi4.index, 0); + + let bi5 = indexer.bloom_index(16, 1); + assert_eq!(bi5.level, 1); + assert_eq!(bi5.index, 1); + + let bi6 = indexer.bloom_index(255, 2); + assert_eq!(bi6.level, 2); + assert_eq!(bi6.index, 0); + + let bi7 = indexer.bloom_index(256, 2); + assert_eq!(bi7.level, 2); + assert_eq!(bi7.index, 1); + } + + #[test] + fn test_lower_level_bloom_indexes() { + let indexer = Indexer::new(16, 3); + + let bi = indexer.bloom_index(256, 2); + assert_eq!(bi.level, 2); + assert_eq!(bi.index, 1); + + let mut ebis = vec![]; + for i in 16..32 { + ebis.push(BloomIndex::new(1, i)); + } + + let bis = indexer.lower_level_bloom_indexes(&bi); + assert_eq!(ebis, bis); + } +} diff --git a/ethcore/src/chainfilter/logs.txt b/ethcore/src/chainfilter/logs.txt new file mode 100644 index 000000000..2127af242 --- /dev/null +++ b/ethcore/src/chainfilter/logs.txt @@ -0,0 +1,1013 @@ +300054 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4d617274696e0000000000000000000000000000000000000000000000000000 +300059 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000059 +300221 0xef2d6d194084c2de36e0dabfce45d046b37d1106 0x02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc +301826 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +303166 0xef2d6d194084c2de36e0dabfce45d046b37d1106 0x6c692d39f4045f32ff9259df5b527f0ebf04abdbbb44231574a0e5398ff21fae 0x0000000000000000000000000000000000000000000000000000000000000738 +303345 0xef2d6d194084c2de36e0dabfce45d046b37d1106 0x02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc +303379 0xe881af13bf55c97562fe8d2da2f6ea8e3ff66f98 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x0000000000000000000000000000000000000000000000000000000000000000 +303379 0xe881af13bf55c97562fe8d2da2f6ea8e3ff66f98 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000000000000000000000000000000000000000000000 +303388 0xe881af13bf55c97562fe8d2da2f6ea8e3ff66f98 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x000000000000000000000000abad6ec946eff02b22e4050b3209da87380b3cbd 0x0000000000000000000000000000000000000000000000000000000000000001 +303388 0xe881af13bf55c97562fe8d2da2f6ea8e3ff66f98 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000000000000000000000000000000000000000000001 +303621 0x584aeb8bcb61e5c1a84d167c2511abf581713495 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 0x00000000000000000000000071353366b3ca768968ea084167655e1cc09938f2 0x000000000000000000000000302f330f8fb5f122b388acb8d85ccb0e712bb5ff +303670 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +303674 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +303683 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +303689 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +303689 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +303692 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +303692 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +303716 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +303717 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +303748 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +303756 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +303756 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +303758 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +303758 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +304090 0x9c667b7ea8ac2a0cc7e73544625d692f72175489 0x17eed4a0a175f46e59877d4b2bd56f2ed7d59d3d1b2dfa7b0867183c528423f8 0x0000000000000000000000000000000000000000000000000000000000000001 +304095 0x9c667b7ea8ac2a0cc7e73544625d692f72175489 0x17eed4a0a175f46e59877d4b2bd56f2ed7d59d3d1b2dfa7b0867183c528423f8 0x0000000000000000000000000000000000000000000000000000000000000002 +304107 0x9c667b7ea8ac2a0cc7e73544625d692f72175489 0x17eed4a0a175f46e59877d4b2bd56f2ed7d59d3d1b2dfa7b0867183c528423f8 0x0000000000000000000000000000000000000000000000000000000000000003 +304113 0x9c667b7ea8ac2a0cc7e73544625d692f72175489 0x17eed4a0a175f46e59877d4b2bd56f2ed7d59d3d1b2dfa7b0867183c528423f8 0x0000000000000000000000000000000000000000000000000000000000000004 +304222 0x9c667b7ea8ac2a0cc7e73544625d692f72175489 0x17eed4a0a175f46e59877d4b2bd56f2ed7d59d3d1b2dfa7b0867183c528423f8 0x0000000000000000000000000000000000000000000000000000000000000005 +304245 0x9c667b7ea8ac2a0cc7e73544625d692f72175489 0x17eed4a0a175f46e59877d4b2bd56f2ed7d59d3d1b2dfa7b0867183c528423f8 0x0000000000000000000000000000000000000000000000000000000000000006 +304247 0x4d498b18abcf83a15d3364d7419a4ef382982c7d 0x7d596234f9de8bba372a6b76656b35620eb6a5211bb764a81b1891567aed662a 0x0000000000000000000000000000000000000000000000000000000000000067 +304247 0x9c667b7ea8ac2a0cc7e73544625d692f72175489 0xe1a3670bcee4a697f1f4341b87487549f80e87998434bb9c2c08c73966d0766d 0x0000000000000000000000000000000000000000000000000000000000000006 0x0000000000000000000000000000000000000000000000000000000000000067 0x0000000000000000000000004d498b18abcf83a15d3364d7419a4ef382982c7d +304312 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x506c616e657468657265756d0000000000000000000000000000000000000000 +304319 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x506c616e657468657265756d0000000000000000000000000000000000000000 0x0000000000000000000000008394a052eb6c32fb9defcaabc12fcbd8fea0b8a8 +304319 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x506c616e657468657265756d0000000000000000000000000000000000000000 +304367 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x7261626269740000000000000000000000000000000000000000000000000000 +304375 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xc86aa3e5b1bc5a674de25655f9a3ccf734594e22d008e71d7ede3fe5c93e1384 +304375 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x7261626269740000000000000000000000000000000000000000000000000000 0x000000000000000000000000f50466e3f27955334fff159e9d6e325c11eb85d6 +304375 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x7261626269740000000000000000000000000000000000000000000000000000 +304407 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xc86aa3e5b1bc5a674de25655f9a3ccf734594e22d008e71d7ede3fe5c93e1384 +304431 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +304433 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +304608 0x7d00703c96bcd2b2af420cf165241396528b5e99 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +304609 0x7d00703c96bcd2b2af420cf165241396528b5e99 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +304788 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +304794 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +304819 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +304835 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xc86aa3e5b1bc5a674de25655f9a3ccf734594e22d008e71d7ede3fe5c93e1384 +304849 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +304856 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xc86aa3e5b1bc5a674de25655f9a3ccf734594e22d008e71d7ede3fe5c93e1384 +304862 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xc86aa3e5b1bc5a674de25655f9a3ccf734594e22d008e71d7ede3fe5c93e1384 +304872 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +304881 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +304902 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +304996 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +304999 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xc86aa3e5b1bc5a674de25655f9a3ccf734594e22d008e71d7ede3fe5c93e1384 +305006 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +305010 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xc86aa3e5b1bc5a674de25655f9a3ccf734594e22d008e71d7ede3fe5c93e1384 +305425 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x427573696e657373000000000000000000000000000000000000000000000000 +305425 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x427573696e657373000000000000000000000000000000000000000000000000 0x000000000000000000000000b48dafc23dc5f232f2e7a35a2d2bb1b4ab02c48a +305425 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x427573696e657373000000000000000000000000000000000000000000000000 +305445 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4574686572000000000000000000000000000000000000000000000000000000 +305448 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4574686572000000000000000000000000000000000000000000000000000000 0x000000000000000000000000b56aea97a14a10f536fa4f770b900e12231a018e +305448 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4574686572000000000000000000000000000000000000000000000000000000 +305450 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x46756e64696e6700000000000000000000000000000000000000000000000000 +305452 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x46756e64696e6700000000000000000000000000000000000000000000000000 0x000000000000000000000000ace8a25b438c0d8c16cf578ddeb015fd1f714896 +305452 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x46756e64696e6700000000000000000000000000000000000000000000000000 +305454 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x436f696e00000000000000000000000000000000000000000000000000000000 +305457 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x7266696b6b690000000000000000000000000000000000000000000000000000 +305463 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6461690000000000000000000000000000000000000000000000000000000000 +305464 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x6461690000000000000000000000000000000000000000000000000000000000 0x000000000000000000000000968ea5eed1d40486a7f87991c3299d383a8e85d2 +305464 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6461690000000000000000000000000000000000000000000000000000000000 +305468 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x77656966756e6400000000000000000000000000000000000000000000000000 +305488 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x5265776172647300000000000000000000000000000000000000000000000000 +305492 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x5553440000000000000000000000000000000000000000000000000000000000 +305492 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x5553440000000000000000000000000000000000000000000000000000000000 0x000000000000000000000000b52f670a662fc87e9a976f50f7ed7c056b369684 +305492 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x5553440000000000000000000000000000000000000000000000000000000000 +305501 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x496e737572616e63650000000000000000000000000000000000000000000000 +305502 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x496e737572616e63650000000000000000000000000000000000000000000000 0x0000000000000000000000004db56c006f6d9e2edf742438c7a7dc032a5c3025 +305502 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x496e737572616e63650000000000000000000000000000000000000000000000 +305510 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x5365780000000000000000000000000000000000000000000000000000000000 +305616 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x43616d706169676e000000000000000000000000000000000000000000000000 +305620 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x43616d706169676e000000000000000000000000000000000000000000000000 0x00000000000000000000000076ff1940d6c15ae2ef8436de7564485770356076 +305620 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x43616d706169676e000000000000000000000000000000000000000000000000 +305622 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4769667463617264000000000000000000000000000000000000000000000000 +305624 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4769667463617264000000000000000000000000000000000000000000000000 0x000000000000000000000000f8aaa4ccb80d0e047e9293619b47160e2c3b82d8 +305624 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4769667463617264000000000000000000000000000000000000000000000000 +305626 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4c6f616e73000000000000000000000000000000000000000000000000000000 +305626 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4c6f616e73000000000000000000000000000000000000000000000000000000 0x000000000000000000000000569a16c067a308a5ea90b15a7caeae8705500569 +305626 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4c6f616e73000000000000000000000000000000000000000000000000000000 +305627 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x53686f7070696e67000000000000000000000000000000000000000000000000 +305629 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x53686f7070696e67000000000000000000000000000000000000000000000000 0x00000000000000000000000068057d1adb313d52890691adf051df3000a3d57d +305629 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x53686f7070696e67000000000000000000000000000000000000000000000000 +305634 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4164647265737300000000000000000000000000000000000000000000000000 +305634 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4164647265737300000000000000000000000000000000000000000000000000 0x000000000000000000000000ea5511d3653d36fb55b53948d23e55a23c4fead7 +305634 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4164647265737300000000000000000000000000000000000000000000000000 +305826 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4d6f6e6579000000000000000000000000000000000000000000000000000000 +305827 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4d6f6e6579000000000000000000000000000000000000000000000000000000 0x000000000000000000000000ef15babca7a972f141556571e5b08e3175cf97b2 +305827 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4d6f6e6579000000000000000000000000000000000000000000000000000000 +305829 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x436f75706f6e7300000000000000000000000000000000000000000000000000 +305834 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x436f75706f6e7300000000000000000000000000000000000000000000000000 0x000000000000000000000000a6cee167a6c4a531c6d16fdff7aa2de9f861cb07 +305834 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x436f75706f6e7300000000000000000000000000000000000000000000000000 +305839 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4163636f756e7400000000000000000000000000000000000000000000000000 +305841 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4163636f756e7400000000000000000000000000000000000000000000000000 0x0000000000000000000000000ec0d6547c59c38a9105525f0c10ec4d4a0b1afb +305841 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4163636f756e7400000000000000000000000000000000000000000000000000 +306889 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +307290 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +307508 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x5858580000000000000000000000000000000000000000000000000000000000 +307509 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x5858580000000000000000000000000000000000000000000000000000000000 0x000000000000000000000000a61bfbbe1af5fde18193ffeffe9254b939d6de96 +307509 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x5858580000000000000000000000000000000000000000000000000000000000 +307513 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x537572696e616d65000000000000000000000000000000000000000000000000 +307519 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x546f797300000000000000000000000000000000000000000000000000000000 +307528 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x5757570000000000000000000000000000000000000000000000000000000000 +308010 0x37c8f253d780913bc2b2d63c4f13f991a9ce7880 0x02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc +308115 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +308124 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +308127 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +308157 0xd202f28e78e9802a95fe5b3d26785257fcf8493b 0xfb989cb0d132b51483b9258c1befbe92caa5f5b046af3dfdcc617dcf425af493 +308183 0x58db357c28947271c883b11bab4caaa445e0ebc0 0x02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc +308190 0xd202f28e78e9802a95fe5b3d26785257fcf8493b 0xfb989cb0d132b51483b9258c1befbe92caa5f5b046af3dfdcc617dcf425af493 +308216 0x59a964f830b3593af88b3d5b2835938d7985fbae 0x02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc +308224 0xd202f28e78e9802a95fe5b3d26785257fcf8493b 0xfb989cb0d132b51483b9258c1befbe92caa5f5b046af3dfdcc617dcf425af493 +308257 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +308265 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +308267 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +308268 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +308285 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +308599 0xc699608dd050d140e37cd402efe8343abcce6cd3 0x9ce147531995c591b0b50012b20f7f6d0dea75281159a58b8637542388f14626 0x00000000000000000000000048175da4c20313bcb6b62d74937d3ff985885701 0x00000000000000000000000023b666fd0ef4778c7557c3e33b126c1f10211941 0xffffffffffffffffffffffffffffffffa0e7153557ae4b988c928492845e7919 +309175 0xfae0d03c4e98022a8c5f35843925d36baf0e51b3 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +309177 0xfae0d03c4e98022a8c5f35843925d36baf0e51b3 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +309184 0xfae0d03c4e98022a8c5f35843925d36baf0e51b3 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +309186 0xfae0d03c4e98022a8c5f35843925d36baf0e51b3 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +309190 0xfae0d03c4e98022a8c5f35843925d36baf0e51b3 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +309194 0xfae0d03c4e98022a8c5f35843925d36baf0e51b3 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +309198 0xfae0d03c4e98022a8c5f35843925d36baf0e51b3 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +309417 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +309881 0x80603decb9f6326b05fec23c9a830d6cf506aa88 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +309883 0x80603decb9f6326b05fec23c9a830d6cf506aa88 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +309892 0x80603decb9f6326b05fec23c9a830d6cf506aa88 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +310069 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xc86aa3e5b1bc5a674de25655f9a3ccf734594e22d008e71d7ede3fe5c93e1384 +310114 0x89c7776f8ae736ce12a0b3309bcea8b4d24bfb12 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +310116 0x89c7776f8ae736ce12a0b3309bcea8b4d24bfb12 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +310177 0x89c7776f8ae736ce12a0b3309bcea8b4d24bfb12 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +310177 0x89c7776f8ae736ce12a0b3309bcea8b4d24bfb12 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +310177 0x89c7776f8ae736ce12a0b3309bcea8b4d24bfb12 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +310533 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xc86aa3e5b1bc5a674de25655f9a3ccf734594e22d008e71d7ede3fe5c93e1384 +310589 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +310592 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +310599 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +310601 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +310604 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +311317 0xfae0d03c4e98022a8c5f35843925d36baf0e51b3 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +311758 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +311858 0xb912acab51206235b6082bcbd2cb88a5fb485a8f 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +311859 0xb912acab51206235b6082bcbd2cb88a5fb485a8f 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +311865 0xb912acab51206235b6082bcbd2cb88a5fb485a8f 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +311888 0xb912acab51206235b6082bcbd2cb88a5fb485a8f 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +312096 0xb7871c70fcba963f502f5b25ca39932820f23206 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +312124 0xb7871c70fcba963f502f5b25ca39932820f23206 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +312124 0xb7871c70fcba963f502f5b25ca39932820f23206 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +312367 0x5e50225b8dccefd89dcbae96e73f71e59a4e2529 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +312371 0x5e50225b8dccefd89dcbae96e73f71e59a4e2529 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +312383 0x5e50225b8dccefd89dcbae96e73f71e59a4e2529 0xe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6 +313355 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +313368 0xb70ca79ffad5f6ddff259bd07089a9c771e32711 0xc86aa3e5b1bc5a674de25655f9a3ccf734594e22d008e71d7ede3fe5c93e1384 +313507 0x8465dac1172b6abe303bead4d06125aed72ea01c 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +313526 0x8465dac1172b6abe303bead4d06125aed72ea01c 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +313724 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +313789 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +314190 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +314375 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000005a +315698 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +315705 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +315780 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +316726 0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +316726 0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +316747 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +317179 0x035e62c27a2338d6ed147ec45d2779990a4c3b00 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +317522 0xe881af13bf55c97562fe8d2da2f6ea8e3ff66f98 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x000000000000000000000000abad6ec946eff02b22e4050b3209da87380b3cbd 0x0000000000000000000000000000000000000000000000000000000000000002 +317522 0xe881af13bf55c97562fe8d2da2f6ea8e3ff66f98 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000000000000000000000000000000000000000000002 +317526 0xb4a953f12f7418ed498a782ba47e5a7f5967091c 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +317536 0xe881af13bf55c97562fe8d2da2f6ea8e3ff66f98 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000000000000000000000000000000000000000000003 +317536 0xe881af13bf55c97562fe8d2da2f6ea8e3ff66f98 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000000000000000000000000000000000000000000003 +317567 0xb4a953f12f7418ed498a782ba47e5a7f5967091c 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +317567 0xc630a71b2dfbcc621affd33257132b50adbe1cd0 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +317588 0xc630a71b2dfbcc621affd33257132b50adbe1cd0 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +317597 0xc630a71b2dfbcc621affd33257132b50adbe1cd0 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +317597 0xc630a71b2dfbcc621affd33257132b50adbe1cd0 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +317606 0xc630a71b2dfbcc621affd33257132b50adbe1cd0 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +317610 0xc630a71b2dfbcc621affd33257132b50adbe1cd0 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +317610 0xb4a953f12f7418ed498a782ba47e5a7f5967091c 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +317610 0xc630a71b2dfbcc621affd33257132b50adbe1cd0 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +317643 0xb4a953f12f7418ed498a782ba47e5a7f5967091c 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +317643 0x1c776e19850998177a7e33f6496c368bcabdce54 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +317646 0x1c776e19850998177a7e33f6496c368bcabdce54 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +317646 0xc630a71b2dfbcc621affd33257132b50adbe1cd0 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +317660 0xe881af13bf55c97562fe8d2da2f6ea8e3ff66f98 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000000000000000000000000000000000000000000004 +317660 0xe881af13bf55c97562fe8d2da2f6ea8e3ff66f98 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000000000000000000000000000000000000000000004 +317957 0x8465dac1172b6abe303bead4d06125aed72ea01c 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +318030 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +318032 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +318033 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x0000000000000000000000000000000000000000000000000000000000000000 0x0000000000000000000000005ed8cee6b63b1c6afce3ad7c92f4fd7e1b8fad9f +318033 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000000000000000000000000000000000000000000000 +318034 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +318036 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +318036 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +318063 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x0000000000000000000000000000000000000000000000000000000000000001 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 +318063 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x0000000000000000000000005ed8cee6b63b1c6afce3ad7c92f4fd7e1b8fad9f 0x0000000000000000000000000000000000000000000000000000000000000001 +318074 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xcfa82ef0390c8f3e57ebe6c0665352a383667e792af012d350d9786ee5173d26 0x0000000000000000000000000000000000000000000000000000000000000000 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 +318074 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xd73429fe3d5eae9e487e60af3e9befceddbdbd53695543a735e2d8face8269d3 0x0000000000000000000000000000000000000000000000000000000000000000 +318096 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x0000000000000000000000000000000000000000000000000000000000000002 0x0000000000000000000000005ed8cee6b63b1c6afce3ad7c92f4fd7e1b8fad9f +318096 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000000000000000000000000000000000000000000002 +318137 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +318528 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x0000000000000000000000000000000000000000000000000000000000000003 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 +318528 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000005ed8cee6b63b1c6afce3ad7c92f4fd7e1b8fad9f 0x0000000000000000000000000000000000000000000000000000000000000003 +318627 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x0000000000000000000000000000000000000000000000000000000000000004 0x0000000000000000000000005ed8cee6b63b1c6afce3ad7c92f4fd7e1b8fad9f +318627 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x0000000000000000000000000000000000000000000000000000000000000004 +318639 0x82afa2c4a686af9344e929f9821f3e8c6e9293ab 0x17af63cbc1fd2f415358d4edda52ede90159c09397285dcedaecb33c5a6d5e02 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 +318639 0x82afa2c4a686af9344e929f9821f3e8c6e9293ab 0x82add6dcb5f515082d024c78eb6496fd6d7e1a037e33403f23188b6c568336e8 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 +318650 0x82afa2c4a686af9344e929f9821f3e8c6e9293ab 0x82add6dcb5f515082d024c78eb6496fd6d7e1a037e33403f23188b6c568336e8 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 +318653 0x82afa2c4a686af9344e929f9821f3e8c6e9293ab 0xc0c8fdc5261cd471b4cf986e1dc55c83e67bab22ff35c3a1e32ab700b8b7eef7 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 +318904 0xc630a71b2dfbcc621affd33257132b50adbe1cd0 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +319523 0x7b6556b40a5a4d40118387495314f4445986239c 0x6c2b4666ba8da5a95717621d879a77de725f3d816709b9cbe9f059b8f875e284 +321346 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +321884 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +321900 0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +322038 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +322041 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +322043 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +322047 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +322048 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +322056 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +322059 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x0000000000000000000000000000000000000000000000000000000000000005 0x0000000000000000000000005ed8cee6b63b1c6afce3ad7c92f4fd7e1b8fad9f +322059 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x0000000000000000000000000000000000000000000000000000000000000005 +322083 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +322090 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +322108 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xcfa82ef0390c8f3e57ebe6c0665352a383667e792af012d350d9786ee5173d26 0x0000000000000000000000000000000000000000000000000000000000000002 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 +322108 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xd73429fe3d5eae9e487e60af3e9befceddbdbd53695543a735e2d8face8269d3 0x0000000000000000000000000000000000000000000000000000000000000002 +322121 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xcfa82ef0390c8f3e57ebe6c0665352a383667e792af012d350d9786ee5173d26 0x0000000000000000000000000000000000000000000000000000000000000003 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 +322121 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xd73429fe3d5eae9e487e60af3e9befceddbdbd53695543a735e2d8face8269d3 0x0000000000000000000000000000000000000000000000000000000000000003 +322121 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xcfa82ef0390c8f3e57ebe6c0665352a383667e792af012d350d9786ee5173d26 0x0000000000000000000000000000000000000000000000000000000000000005 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 +322121 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xd73429fe3d5eae9e487e60af3e9befceddbdbd53695543a735e2d8face8269d3 0x0000000000000000000000000000000000000000000000000000000000000005 +322122 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xcfa82ef0390c8f3e57ebe6c0665352a383667e792af012d350d9786ee5173d26 0x0000000000000000000000000000000000000000000000000000000000000001 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 +322122 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xd73429fe3d5eae9e487e60af3e9befceddbdbd53695543a735e2d8face8269d3 0x0000000000000000000000000000000000000000000000000000000000000001 +322128 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xcfa82ef0390c8f3e57ebe6c0665352a383667e792af012d350d9786ee5173d26 0x0000000000000000000000000000000000000000000000000000000000000004 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 +322128 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0xd73429fe3d5eae9e487e60af3e9befceddbdbd53695543a735e2d8face8269d3 0x0000000000000000000000000000000000000000000000000000000000000004 +322454 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x63726f0000000000000000000000000000000000000000000000000000000000 +322509 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x63726f0000000000000000000000000000000000000000000000000000000000 0x000000000000000000000000d388d8671ac6edb904d91c1585dedbd6895b9ef8 +322509 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x63726f0000000000000000000000000000000000000000000000000000000000 +322550 0x8465dac1172b6abe303bead4d06125aed72ea01c 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +322749 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x1250e52636eed438f884679df55d2911cf41764cf8b2da1bd22d29b0eb14f80e 0x0000000000000000000000000000000000000000000000000000000000000006 0x0000000000000000000000005ed8cee6b63b1c6afce3ad7c92f4fd7e1b8fad9f +322749 0x7e2d0fe0ffdd78c264f8d40d19acb7d04390c6e8 0x8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba 0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045 0x0000000000000000000000001db3439a222c519ab44bb1144fc28167b4fa6ee6 0x0000000000000000000000000000000000000000000000000000000000000006 +322750 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x41756374696f6e00000000000000000000000000000000000000000000000000 +322752 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x41756374696f6e00000000000000000000000000000000000000000000000000 0x000000000000000000000000fd5c601a0d48ad075724af920a83b907d24620dd +322752 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x41756374696f6e00000000000000000000000000000000000000000000000000 +322758 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4d6f727467616765000000000000000000000000000000000000000000000000 +322760 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4d6f727467616765000000000000000000000000000000000000000000000000 0x000000000000000000000000f32d6e7a9ae9c3d59b642fcfa95c0f03c0706561 +322760 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4d6f727467616765000000000000000000000000000000000000000000000000 +322764 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x457363726f770000000000000000000000000000000000000000000000000000 +322765 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x457363726f770000000000000000000000000000000000000000000000000000 0x000000000000000000000000091a096c2c75cd3bd6a80a8104a4c71a6f028483 +322765 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x457363726f770000000000000000000000000000000000000000000000000000 +322767 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x47756172616e7465650000000000000000000000000000000000000000000000 +322768 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x47756172616e7465650000000000000000000000000000000000000000000000 0x000000000000000000000000439061363c1502dcb8ce7b08dab39b5aa321adf2 +322768 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x47756172616e7465650000000000000000000000000000000000000000000000 +322774 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x53616665436f6e74726163747300000000000000000000000000000000000000 +322776 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x53616665436f6e74726163747300000000000000000000000000000000000000 0x0000000000000000000000002e6bfa82463744c2b1254f119fa101bc924f6f0b +322776 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x53616665436f6e74726163747300000000000000000000000000000000000000 +322777 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x53616665436f6e74726163740000000000000000000000000000000000000000 +322777 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x53616665436f6e74726163740000000000000000000000000000000000000000 0x0000000000000000000000009a5cb02980fbae601ed890f01d38be76a47d8eeb +322777 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x53616665436f6e74726163740000000000000000000000000000000000000000 +324029 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +324316 0x4d8875b5058c6bf9db0fba172114299eaa476a9d 0x8f38ec1c60ec4afc7e3dd2c41a94c0983104d82de715c0212bbfe4aca17ea3fb +324318 0x4d8875b5058c6bf9db0fba172114299eaa476a9d 0x5b6450564c0cb96f02986ab222d919319391faea73418fec4158904af177cdeb +324322 0x4d8875b5058c6bf9db0fba172114299eaa476a9d 0x80bb6e5f203cdbe2810b6446806301f07413ca83c2a9c7b0c1cc5b89853a55dd +325807 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +326760 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000002b051365221244a2baefb07e7ac1a291893e0867 +326760 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000002b051365221244a2baefb07e7ac1a291893e0867 +327103 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +327105 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +327227 0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +327399 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +327399 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +327544 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +327544 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +327690 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000041c32b2f3c0e04b20d2c4f1605f0abc33c3cad67 +327690 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000041c32b2f3c0e04b20d2c4f1605f0abc33c3cad67 +328002 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000005b +328269 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +328529 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +328529 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +328585 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000d51059a3dedfa8032a64361a883a53e26ed6941c +328585 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000d51059a3dedfa8032a64361a883a53e26ed6941c +328870 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +328870 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +329480 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4368696e61000000000000000000000000000000000000000000000000000000 +329484 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4368696e61000000000000000000000000000000000000000000000000000000 0x00000000000000000000000080f3a701a57961f57752397d24a45f87127c361a +329484 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4368696e61000000000000000000000000000000000000000000000000000000 +329485 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000076b0f6b32c66c317699067f2d938bcf669f380ce +329485 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000076b0f6b32c66c317699067f2d938bcf669f380ce +329491 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000076b0f6b32c66c317699067f2d938bcf669f380ce +329491 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000076b0f6b32c66c317699067f2d938bcf669f380ce +329513 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000076b0f6b32c66c317699067f2d938bcf669f380ce +329513 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000076b0f6b32c66c317699067f2d938bcf669f380ce +329519 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000076b0f6b32c66c317699067f2d938bcf669f380ce +329519 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000076b0f6b32c66c317699067f2d938bcf669f380ce +329659 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x5469636b65740000000000000000000000000000000000000000000000000000 +329659 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x5469636b65740000000000000000000000000000000000000000000000000000 0x0000000000000000000000009f26df964012d16fdea7485bd4b7042b3007e217 +329659 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x5469636b65740000000000000000000000000000000000000000000000000000 +329667 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x446174696e670000000000000000000000000000000000000000000000000000 +329668 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x446174696e670000000000000000000000000000000000000000000000000000 0x000000000000000000000000f5f5d1595aa8eca29cfdc9b62357f01c33d9bf20 +329668 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x446174696e670000000000000000000000000000000000000000000000000000 +329673 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x43616e6479000000000000000000000000000000000000000000000000000000 +329673 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x43616e6479000000000000000000000000000000000000000000000000000000 0x000000000000000000000000f41830acc2a73021ff1c3381ac570b95d79d21d0 +329673 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x43616e6479000000000000000000000000000000000000000000000000000000 +329740 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000005c +329749 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x57616c6c73747265657400000000000000000000000000000000000000000000 +329750 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x57616c6c73747265657400000000000000000000000000000000000000000000 0x0000000000000000000000002fed81f556a6f7478249fadbb68621467e21d38c +329750 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x57616c6c73747265657400000000000000000000000000000000000000000000 +329824 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000005c08761401d1a0904897c978787aa615a96e955c +329824 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000005c08761401d1a0904897c978787aa615a96e955c +329964 0xb8af70f84bfda39ccb2858f4fc54eca1b63dd519 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +330023 0xb8af70f84bfda39ccb2858f4fc54eca1b63dd519 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +330207 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000e0ed85f0cab17dba645bf4fe745ca29359c2c21b +330207 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000e0ed85f0cab17dba645bf4fe745ca29359c2c21b +330473 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000042244ccb6c7c889901960e60125ead7c2af685f8 +330473 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000042244ccb6c7c889901960e60125ead7c2af685f8 +330511 0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +330511 0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +330579 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000c550f754865b1ad138b660c9802ee8b039abb05b +330579 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000c550f754865b1ad138b660c9802ee8b039abb05b +330683 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000cffa3a1af763ccb260f4bf081f8a1bfddfdb89e0 +330683 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000cffa3a1af763ccb260f4bf081f8a1bfddfdb89e0 +330919 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a4145a98b12b717078b96821124d781c563511ca +330919 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a4145a98b12b717078b96821124d781c563511ca +331009 0x53bccda5dcacc0b10b7c4145b0aa6581330b8635 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +331542 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000003090aef28f1a9a4d1d9f9b8fc26d28ad1240214f +331542 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000003090aef28f1a9a4d1d9f9b8fc26d28ad1240214f +332007 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000aa3e4fd68c8fabd386fc571f9656e50dba5dd384 +332007 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000aa3e4fd68c8fabd386fc571f9656e50dba5dd384 +333256 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000009dca2265990b7ad9ac5c3a55157f1fc9d18381bc +333256 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000009dca2265990b7ad9ac5c3a55157f1fc9d18381bc +333294 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +333583 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000ff6c2227335eb7d5b29d86a8f78f35d4b9bafd3a +333583 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000ff6c2227335eb7d5b29d86a8f78f35d4b9bafd3a +333640 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000601ee21411eba5a5bc9d1c6298822a1a7b9e2286 +333640 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000601ee21411eba5a5bc9d1c6298822a1a7b9e2286 +334263 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000691ee952cf68d9abc488e42f5c1f95c020651333 +334263 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000691ee952cf68d9abc488e42f5c1f95c020651333 +334279 0xbd0edfbac386c9964f8f013d65d7dad5382d9cd7 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +334883 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000005d +334915 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000005e +334919 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000005f +334919 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000007d1ecf34b360f75280b83abc04f654ac99c7bd9c +334919 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000007d1ecf34b360f75280b83abc04f654ac99c7bd9c +335076 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000367a3da4c3aa4c4b9de2c01bdca8075593c7ff1e +335076 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000367a3da4c3aa4c4b9de2c01bdca8075593c7ff1e +335348 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000009d8048c450677dcd0b6c37c6a989a54a2a506a27 +335348 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000009d8048c450677dcd0b6c37c6a989a54a2a506a27 +335643 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +335649 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +335649 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +335652 0x5f4c010748a890c8a28a4858fe7b07048d194380 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +335684 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000d80b5d0763ceaf00e3c457c54acc880a6317d057 +335684 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000d80b5d0763ceaf00e3c457c54acc880a6317d057 +336089 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000866d22bf02ad128c2e015a27ed39c7f5f0bd65f3 +336089 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000866d22bf02ad128c2e015a27ed39c7f5f0bd65f3 +336231 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336234 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336242 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336243 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336244 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336245 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336245 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336247 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336248 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336255 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336260 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336263 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336264 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336266 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336266 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336334 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336336 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336337 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336338 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336439 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336451 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336452 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336453 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336453 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336461 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336495 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336497 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336497 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336497 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336507 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336508 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336508 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336508 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336508 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336508 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336509 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336510 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336510 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336510 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336518 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336520 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336521 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336522 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336526 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336527 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336528 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336528 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336543 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +336543 0x5dc2e401e29ea16e51ebcecaef129c15fed5a5e8 0xd456720fd185d4060f5cea4d82775d2af95048c1e10f227ec35bae950a4be2a8 0x0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e2 +337012 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000f2c453692a6f46cffd30943fe9bee65cac3622d7 +337012 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000f2c453692a6f46cffd30943fe9bee65cac3622d7 +337642 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x456475636174696f6e0000000000000000000000000000000000000000000000 +337642 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x456475636174696f6e0000000000000000000000000000000000000000000000 0x00000000000000000000000002ef13dd4479f121b4636bc3d7ea9da774b3ed74 +337642 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x456475636174696f6e0000000000000000000000000000000000000000000000 +337647 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x50686f6e65000000000000000000000000000000000000000000000000000000 +337649 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x50686f6e65000000000000000000000000000000000000000000000000000000 0x0000000000000000000000003210743d3b82ec01338c50d64ce97de5e8ec94bb +337649 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x50686f6e65000000000000000000000000000000000000000000000000000000 +337653 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x506f6b6572000000000000000000000000000000000000000000000000000000 +337654 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x506f6b6572000000000000000000000000000000000000000000000000000000 0x000000000000000000000000d0dc4dac9c29cacd9dcd6d7f7ca97e04b0ba6e09 +337654 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x506f6b6572000000000000000000000000000000000000000000000000000000 +337655 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x50726f7065727479000000000000000000000000000000000000000000000000 +337656 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x50726f7065727479000000000000000000000000000000000000000000000000 0x00000000000000000000000097eb80f6d0777baa9bbcc8722b43e3e88d00efaf +337656 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x50726f7065727479000000000000000000000000000000000000000000000000 +337663 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x53616c6573000000000000000000000000000000000000000000000000000000 +337663 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x53616c6573000000000000000000000000000000000000000000000000000000 0x0000000000000000000000004ad03d890ef08dbae952527c829d0dde8d31c3b7 +337663 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x53616c6573000000000000000000000000000000000000000000000000000000 +337664 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4d61726b65740000000000000000000000000000000000000000000000000000 +337669 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x486f757365000000000000000000000000000000000000000000000000000000 +337672 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x486f757365000000000000000000000000000000000000000000000000000000 0x0000000000000000000000000ec0d6547c59c38a9105525f0c10ec4d4a0b1afb +337672 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x486f757365000000000000000000000000000000000000000000000000000000 +337731 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000f80675f372ff20d0a5f3bc82a51c8fb9fb5022cd +337731 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000f80675f372ff20d0a5f3bc82a51c8fb9fb5022cd +338275 0x9f918d46c929f12a229b6084566384ee26805b4d 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +338281 0x9f918d46c929f12a229b6084566384ee26805b4d 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +338336 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +338424 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000008a66d1381b139ec676e522aeab6fd82cc78567d +338424 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000008a66d1381b139ec676e522aeab6fd82cc78567d +338435 0x8056338e73fde306bb5d9aedec7f4a7b8637c9e7 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +338439 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000065e9201879e2a6ff7da133f0c573a8fe5d9da7ca +338439 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000065e9201879e2a6ff7da133f0c573a8fe5d9da7ca +338661 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +338661 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +338991 0x0e5e2b9341341ade98f510ad9a744e01f3b29f03 0x1cf7652f1f9289dc41763c5bd36534c9772d48aa26021274d212f227d4b69765 0x0000000000000000000000000000000000000000000000000000000000000060 +339173 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000049f47bc027e273e21f46000c49971919b3e15773 +339173 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000049f47bc027e273e21f46000c49971919b3e15773 +339369 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000060 +339427 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000f3b83292f3e56f4aec1e3c44128d0f1a9d824559 +339427 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000f3b83292f3e56f4aec1e3c44128d0f1a9d824559 +340633 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x42697447656d7300000000000000000000000000000000000000000000000000 +340635 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x42697447656d7300000000000000000000000000000000000000000000000000 0x000000000000000000000000c34f6222062c65e35d4b0fc26d718738582118a6 +340635 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x42697447656d7300000000000000000000000000000000000000000000000000 +340653 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4469616d6f6e6473000000000000000000000000000000000000000000000000 +340658 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4469616d6f6e6473000000000000000000000000000000000000000000000000 0x0000000000000000000000004e971507462271eadb8aac0d20312099f6d52947 +340658 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4469616d6f6e6473000000000000000000000000000000000000000000000000 +340674 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x476f6c6400000000000000000000000000000000000000000000000000000000 +340675 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x476f6c6400000000000000000000000000000000000000000000000000000000 0x000000000000000000000000eb26edf39a4ad0a3b8d6a9804b4e2a7b47d3017b +340675 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x476f6c6400000000000000000000000000000000000000000000000000000000 +340685 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4469676978000000000000000000000000000000000000000000000000000000 +340686 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4469676978000000000000000000000000000000000000000000000000000000 0x0000000000000000000000000b3765d911cbf67fd92f4d3e5cc25211ddc743de +340686 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4469676978000000000000000000000000000000000000000000000000000000 +340700 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x426f617264726f6f6d0000000000000000000000000000000000000000000000 +340700 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x426f617264726f6f6d0000000000000000000000000000000000000000000000 0x000000000000000000000000c8cfec0ee1d4802daaae1bebb07aa7c44931e633 +340700 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x426f617264726f6f6d0000000000000000000000000000000000000000000000 +340708 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x45786368616e6765000000000000000000000000000000000000000000000000 +340710 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x45786368616e6765000000000000000000000000000000000000000000000000 0x0000000000000000000000005492f79ca66506bc751862ba35a9121d8b28532d +340710 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x45786368616e6765000000000000000000000000000000000000000000000000 +340712 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x426974636f696e00000000000000000000000000000000000000000000000000 +340713 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x426974636f696e00000000000000000000000000000000000000000000000000 0x000000000000000000000000a9033165b71f08ac82c53d5f982b463ca5301c15 +340713 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x426974636f696e00000000000000000000000000000000000000000000000000 +340718 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x426974636f696e73000000000000000000000000000000000000000000000000 +340719 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x426974636f696e73000000000000000000000000000000000000000000000000 0x000000000000000000000000f301f8e2cc1bab42ced9902f1fcd1a25303823db +340719 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x426974636f696e73000000000000000000000000000000000000000000000000 +340727 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4d61696c00000000000000000000000000000000000000000000000000000000 +340727 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x4d61696c00000000000000000000000000000000000000000000000000000000 0x0000000000000000000000004143c2f1563da14b2c09559ef5144b4c6ca268fe +340727 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x4d61696c00000000000000000000000000000000000000000000000000000000 +340728 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x456d61696c000000000000000000000000000000000000000000000000000000 +340835 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +340988 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000008db600d7c92b0182ec527d8972d9e4d67d82e62a +340988 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000008db600d7c92b0182ec527d8972d9e4d67d82e62a +341695 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000351be7a8b083e7e3e3c16744a1fea3420064f60a +341695 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000351be7a8b083e7e3e3c16744a1fea3420064f60a +341985 0xbda7aeb6d2002efe360b6467275ef01e77d15497 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +341997 0xbda7aeb6d2002efe360b6467275ef01e77d15497 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +342001 0xbda7aeb6d2002efe360b6467275ef01e77d15497 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342004 0xbda7aeb6d2002efe360b6467275ef01e77d15497 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342004 0xbda7aeb6d2002efe360b6467275ef01e77d15497 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +342007 0xbda7aeb6d2002efe360b6467275ef01e77d15497 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342007 0xbda7aeb6d2002efe360b6467275ef01e77d15497 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +342008 0xbda7aeb6d2002efe360b6467275ef01e77d15497 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342026 0xc630a71b2dfbcc621affd33257132b50adbe1cd0 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +342026 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342027 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342027 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342033 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342035 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342036 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342041 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +342047 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +342047 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +342047 0xbda7aeb6d2002efe360b6467275ef01e77d15497 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342053 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342053 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +342080 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342080 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342080 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +342101 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +342107 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342107 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +342111 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342111 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +342115 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +342118 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +342118 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342125 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342125 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +342140 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xc7fb647e59b18047309aa15aad418e5d7ca96d173ad704f1031a2c3d7591734b +342141 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342145 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342145 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342145 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +342162 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342162 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +342173 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342173 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +342188 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342188 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +342272 0x65eb93c4e0854e3b00a64cd18c176a7fd54dc50f 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342386 0x65eb93c4e0854e3b00a64cd18c176a7fd54dc50f 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +342386 0x8056338e73fde306bb5d9aedec7f4a7b8637c9e7 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +342399 0x65eb93c4e0854e3b00a64cd18c176a7fd54dc50f 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +342466 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000014a986e0b8943efe13e2f3514878dcd1fe08a677 +342466 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000014a986e0b8943efe13e2f3514878dcd1fe08a677 +342601 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +342601 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +342616 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xc7fb647e59b18047309aa15aad418e5d7ca96d173ad704f1031a2c3d7591734b +342618 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xc7fb647e59b18047309aa15aad418e5d7ca96d173ad704f1031a2c3d7591734b +342924 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000144c12d635ded35f0e0576564b95cf08045cb3ee +342924 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000144c12d635ded35f0e0576564b95cf08045cb3ee +342964 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000c36d3ccea8fb30b8f2c66af05bc3b5433d59168d +342964 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000c36d3ccea8fb30b8f2c66af05bc3b5433d59168d +343006 0x4bcd0591897025a0c42d500b4c37b11de6d96a3c 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +343021 0x4bcd0591897025a0c42d500b4c37b11de6d96a3c 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +343059 0xcf8470d3388a198418e02aaf8e37392cfbc18867 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +343079 0xcf8470d3388a198418e02aaf8e37392cfbc18867 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +343079 0xcf8470d3388a198418e02aaf8e37392cfbc18867 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +343083 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000006fa4aa0d8ce57b5325b1d04708db281bbe95b23b +343083 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000006fa4aa0d8ce57b5325b1d04708db281bbe95b23b +343133 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +343162 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000061 +343185 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000062 +343339 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000b9e893dc7da0b5b3eb9678d4860fb885f92be9cf +343339 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000b9e893dc7da0b5b3eb9678d4860fb885f92be9cf +343946 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +343966 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +343971 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +344121 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000002b051365221244a2baefb07e7ac1a291893e0867 +344121 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000002b051365221244a2baefb07e7ac1a291893e0867 +344164 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000002b051365221244a2baefb07e7ac1a291893e0867 +344164 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000002b051365221244a2baefb07e7ac1a291893e0867 +344839 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000001c3b909facd70e74c5697f1329c2d0cc0dd5ac3e +344839 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000001c3b909facd70e74c5697f1329c2d0cc0dd5ac3e +345506 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +346112 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +346112 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +346392 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +346395 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +346398 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +346425 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +346448 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +346451 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +346454 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +346464 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +346466 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +347014 0xd2d8d510980ef02fb2c3b79479d9b57d3bc7e2e7 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +347301 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000848e4dc353b9962471cd6506adc206f001e15fec +347301 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000848e4dc353b9962471cd6506adc206f001e15fec +347333 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000848e4dc353b9962471cd6506adc206f001e15fec +347333 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000848e4dc353b9962471cd6506adc206f001e15fec +347613 0xad8d3a5d2d92eb14bb56ca9f380be35b8efe0c04 0x4c13017ee95afc4bbd8a701dd9fbc9733f1f09f5a1b5438b5b9abd48e4c92d78 0x5858585858585858580000000000000000000000000000000000000000000000 0x0000000000000000000000000075f6703dad72b3e89f3243b2666a7f1bd815c0 +347700 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +347705 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +347711 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +347711 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +347853 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +347953 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0xc7fb647e59b18047309aa15aad418e5d7ca96d173ad704f1031a2c3d7591734b +347958 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +347958 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +347960 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +347960 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +348019 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +348244 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000fae49cd796d28e8eca3fd701f86864940270a6fe +348244 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000fae49cd796d28e8eca3fd701f86864940270a6fe +348443 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000001819c2a9ff0b2ebdc677b6e8f4ee5c2bd6b73dae +348443 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000001819c2a9ff0b2ebdc677b6e8f4ee5c2bd6b73dae +348675 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000fc039dc8cdba96ab8ceb01c972375b71ddcc6b2e +348675 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000fc039dc8cdba96ab8ceb01c972375b71ddcc6b2e +348743 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +348936 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000b3303a4f7ef21aed2325856caa14417e91ee5404 +348936 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000b3303a4f7ef21aed2325856caa14417e91ee5404 +350544 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +351473 0xebd81a08ded0efaba8ef51924fb967b64aa85399 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +353157 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +353181 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +353196 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +353196 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +353273 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xc7fb647e59b18047309aa15aad418e5d7ca96d173ad704f1031a2c3d7591734b +353276 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +353359 0xe2d560cc321a4e09e182693d45a3836ffd27a1bd 0x302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c +353359 0xfd5ff05cb15b2e8cddd0e96912a5dee8044b9374 0x302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c +353360 0x991c5b56fffb2e45444b5fc5be9304ac9576849b 0x302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c +353361 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000063 +353367 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000064 +353370 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000065 +353438 0x52c6b42c37818ee7d562b52396685710b19801ec 0x302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c +353438 0xf9da1908cc2280578b2639e3a4576dc77624868b 0x302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c +353443 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000066 +353447 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000067 +353479 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000aadd74f71770fbef7325860bce13cff05e3ad1c9 +353479 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000aadd74f71770fbef7325860bce13cff05e3ad1c9 +354071 0x36290e3f7c0e074a9e80cd6eb2f36b77411c19d7 0xa192e48a82f18ef1c93e722713426e5733e98d5b2858ba5c7457faf4a8297dab 0x000000000000000000000000b834e3edfc1a927bdcecb67a9d0eccbd752a5bb3 0x0000000000000000000000000000000000000000000000000000000000056917 +354151 0xdb15058402c241b04a03846f6fb104b1fbeea10b 0x5ca1bad5a7f3ee229aa045a13d9936a9a5f7f70067a0e39bdb8a6c0086b1544c 0xb56c4a1a61178e44bb3c424e54fccd7a48926c8ee43735cfa297f51c116344f1 +354162 0xdb15058402c241b04a03846f6fb104b1fbeea10b 0x5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62 0x000000000000000000000000d3cda913deb6f67967b99d67acdfa1712c293601 0x000000000000000000000000afbc7cedd81c694e8033b101a0b49bfc1e5176e2 +354233 0xdb15058402c241b04a03846f6fb104b1fbeea10b 0xed1062ba7ed13514b41ef115d3c324f50dcd644da75ee5659e9ae97071774f1e 0x000000000000000000000000b834e3edfc1a927bdcecb67a9d0eccbd752a5bb3 0xb56c4a1a61178e44bb3c424e54fccd7a48926c8ee43735cfa297f51c116344f1 +354585 0xdb15058402c241b04a03846f6fb104b1fbeea10b 0x884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364 0x000000000000000000000000afbc7cedd81c694e8033b101a0b49bfc1e5176e2 +354866 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000009b75587d8d49477de8b6e845ccb40d970bf8701a +354866 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000009b75587d8d49477de8b6e845ccb40d970bf8701a +356461 0x84be9f9c3e3dc0721d628a3b8ef55fbe096c0495 0x0000000000000000000000000000000000000000000000000000000000000060 +356488 0xf0ea74d3e2743e880dcf12e731d6bdd5788a548c 0xf2fb068683a2e3c90600f0aab753f44a2340e65156afd0f69518d72b55354ece 0x0000000000000000000000000000000000000000000000000000000000000060 +356513 0x69e3eab0a888f72c161d1f2e4e97eb8f0089af88 0x3fbfa2086703ed2c0e6065c0a6d81aa1ffdf01229d542d9f132b6696db6c66f1 0x9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658 +356526 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +356535 0xaf40044f727b3975174ed30d21a850b2f8619f11 0x7465737400000000000000000000000000000000000000000000000000000000 +356543 0xaf40044f727b3975174ed30d21a850b2f8619f11 0x3963323266663566323166306238316231313365363366376462366461393466 +357195 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +357195 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +357579 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +357588 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +357590 0xcf8470d3388a198418e02aaf8e37392cfbc18867 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +357590 0xcf8470d3388a198418e02aaf8e37392cfbc18867 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +357592 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +357600 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +357622 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +357630 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +358290 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +358290 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +358426 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +358556 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +358556 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +358811 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000b76246acebd335e1af9e2073f684ff6c555816c6 +358811 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000b76246acebd335e1af9e2073f684ff6c555816c6 +359114 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +359114 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +359375 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000068 +359378 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000069 +359378 0x4d6387f3b967da39b11de111158d49754c31985d 0x2dba1d9e78f3192742fc9d510383d669fe8a4fa03d039bd7382ef67119078af7 0x0000000000000000000000000000000000000000000000000000000000000012 +359538 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000006a +361585 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +361585 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +361588 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +361588 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +361732 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000030d9803d6754bd9ad6d3a9990ca7a07af8745d5a +361732 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000030d9803d6754bd9ad6d3a9990ca7a07af8745d5a +361757 0xcf8470d3388a198418e02aaf8e37392cfbc18867 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +361757 0xcf8470d3388a198418e02aaf8e37392cfbc18867 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +361775 0xcf8470d3388a198418e02aaf8e37392cfbc18867 0xc7fb647e59b18047309aa15aad418e5d7ca96d173ad704f1031a2c3d7591734b +362002 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000013a85703f391b8c9abb8068be03ff4d6aebd11eb +362002 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000013a85703f391b8c9abb8068be03ff4d6aebd11eb +365791 0xfd5ff05cb15b2e8cddd0e96912a5dee8044b9374 0x302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c +365793 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000006b +369141 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x0000000000000000000000006407c4286dc1c84aab28720eea596212c026450e +369141 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x0000000000000000000000006407c4286dc1c84aab28720eea596212c026450e +369239 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +369249 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +369253 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +369259 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +369261 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +369263 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +369274 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +369426 0xe2d560cc321a4e09e182693d45a3836ffd27a1bd 0x302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c +369426 0xfd5ff05cb15b2e8cddd0e96912a5dee8044b9374 0x302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c +369428 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000006c +369428 0x4d6387f3b967da39b11de111158d49754c31985d 0x2dba1d9e78f3192742fc9d510383d669fe8a4fa03d039bd7382ef67119078af7 0x0000000000000000000000000000000000000000000000000000000000000013 +369431 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000006d +369538 0xfd5ff05cb15b2e8cddd0e96912a5dee8044b9374 0x302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c +369540 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000006e +370399 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000071dcbc554dada022fdd31333f8883e953240f0b0 +370399 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000071dcbc554dada022fdd31333f8883e953240f0b0 +370517 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +370517 0x36517ccf7a16266de8b7cbd60db1f45a23f1eaf1 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +370545 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +370545 0x36517ccf7a16266de8b7cbd60db1f45a23f1eaf1 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371190 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371280 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371286 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371288 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371299 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371307 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371327 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371327 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371329 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371352 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371360 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371362 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371369 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +371378 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371378 0x36517ccf7a16266de8b7cbd60db1f45a23f1eaf1 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371450 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371450 0x36517ccf7a16266de8b7cbd60db1f45a23f1eaf1 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371489 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371489 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371509 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371509 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371532 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371658 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371658 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371660 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371876 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371876 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371904 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371904 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371906 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371912 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371912 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371914 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371918 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371918 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371931 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371931 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371933 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371938 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371938 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +371940 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371973 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +371973 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +372006 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +372006 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +372014 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +372847 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +374209 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +374225 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +374365 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +374388 0x7fb091d48426f54f6fb8d1a43f8e33f80454f4e3 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +375079 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +375079 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +375093 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +375401 0x4bca74810cc4917a7dee954d21221b72fd87d3d7 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +375440 0x4bca74810cc4917a7dee954d21221b72fd87d3d7 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +375447 0x4bca74810cc4917a7dee954d21221b72fd87d3d7 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +376493 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +376573 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +376588 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +376644 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +376650 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +376668 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +376906 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +377026 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +377026 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +377139 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +377139 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +377506 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +377523 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +377523 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +377525 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +377581 0xfd5ff05cb15b2e8cddd0e96912a5dee8044b9374 0x302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c +377586 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x000000000000000000000000000000000000000000000000000000000000006f +377608 0x8465dac1172b6abe303bead4d06125aed72ea01c 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +377627 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +377627 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +377629 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +377629 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +377703 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +377703 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +377730 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +377730 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +377746 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +377877 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +377877 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +377894 0xb4a953f12f7418ed498a782ba47e5a7f5967091c 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +377905 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +377905 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +377917 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +377917 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +377922 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +377922 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +377925 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +378345 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +378345 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +378347 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +378347 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +379027 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000070 +379032 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000071 +379039 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000072 +379158 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x77656c6661726500000000000000000000000000000000000000000000000000 +379161 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x77656c6661726500000000000000000000000000000000000000000000000000 0x000000000000000000000000266d8a3bfa7536f3f921da30824e47c561dd66cc +379161 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x77656c6661726500000000000000000000000000000000000000000000000000 +379163 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x736f636965747900000000000000000000000000000000000000000000000000 +379164 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x736f636965747900000000000000000000000000000000000000000000000000 0x000000000000000000000000435a8f8bbed708ca75aa1c8ca7091fa1a3c03782 +379164 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x736f636965747900000000000000000000000000000000000000000000000000 +379167 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6461707000000000000000000000000000000000000000000000000000000000 +379170 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +379171 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x6461707000000000000000000000000000000000000000000000000000000000 0x000000000000000000000000f81f0d1f4cacb0a419dba6fa897a121f61347c84 +379171 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6461707000000000000000000000000000000000000000000000000000000000 +379172 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6e6574776f726b00000000000000000000000000000000000000000000000000 +379176 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x6e6574776f726b00000000000000000000000000000000000000000000000000 0x00000000000000000000000030ce983f55cfa6742a1270e263ff33010fb82790 +379176 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6e6574776f726b00000000000000000000000000000000000000000000000000 +379180 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x7765697472616465720000000000000000000000000000000000000000000000 +379182 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x7765697472616465720000000000000000000000000000000000000000000000 0x00000000000000000000000003477c75a6b22c58f8e65ecfb97219541c16aacf +379182 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x7765697472616465720000000000000000000000000000000000000000000000 +379210 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x7065657200000000000000000000000000000000000000000000000000000000 +379212 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x7065657200000000000000000000000000000000000000000000000000000000 0x000000000000000000000000a5fcbfe7e0fe1a8f97772e3ff2433df651c3cd40 +379212 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x7065657200000000000000000000000000000000000000000000000000000000 +379214 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6c65646765720000000000000000000000000000000000000000000000000000 +379216 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x6c65646765720000000000000000000000000000000000000000000000000000 0x0000000000000000000000001bfa9c5206cf2f2d6218468200da6a6b2488f5f1 +379216 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6c65646765720000000000000000000000000000000000000000000000000000 +379217 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6964656e74697479000000000000000000000000000000000000000000000000 +379219 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x6964656e74697479000000000000000000000000000000000000000000000000 0x000000000000000000000000420ec54a21967d9813cd184fa32783b61897b097 +379219 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6964656e74697479000000000000000000000000000000000000000000000000 +379220 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x72657075746174696f6e00000000000000000000000000000000000000000000 +379224 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x72657075746174696f6e00000000000000000000000000000000000000000000 0x000000000000000000000000d9b2f59f3b5c7b3c67047d2f03c3e8052470be92 +379224 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x72657075746174696f6e00000000000000000000000000000000000000000000 +379235 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6c6f747465727900000000000000000000000000000000000000000000000000 +379237 0x33990122638b9132ca29c723bdf037f1a891a70c 0xf63780e752c6a54a94fc52715dbc5518a3b4c3c2833d301a204226548a2a8545 0x6c6f747465727900000000000000000000000000000000000000000000000000 0x0000000000000000000000001f6cc3f7c927e1196c03ac49c5aff0d39c9d103d +379237 0x33990122638b9132ca29c723bdf037f1a891a70c 0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc 0x6c6f747465727900000000000000000000000000000000000000000000000000 +381271 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +381271 0xd53096b3cf64d4739bb774e0f055653e7f2cd710 0x0cee94601ab1f1d758b126c873d5328735356f811c80bdf6af62fe2534db51b6 +381276 0x6acc9a6876739e9190d06463196e27b6d37405c6 0xf7eba460ce397de720ba4749bd9c125fec27d45ef68e15fffe706e8c211a7f5c +381689 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +382200 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000073 +382217 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000074 +382644 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000848e4dc353b9962471cd6506adc206f001e15fec +382644 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000848e4dc353b9962471cd6506adc206f001e15fec +383284 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +383337 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +383354 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +383361 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +383427 0xad8d3a5d2d92eb14bb56ca9f380be35b8efe0c04 0x19dacbf83c5de6658e14cbf7bcae5c15eca2eedecf1c66fbca928e4d351bea0f 0x000000000000000000000000f44058ffe3b8e3a6344e95a7dba8929d5b94bae2 0x4141414141494948490000000000000000000000000000000000000000000000 +383466 0x7f1d234e281ff8421b2b0650a9b8f85b5d73bd59 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +383469 0x51b6b4f5b270fa093198a984c3fce5ea607a94e7 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +383515 0xad8d3a5d2d92eb14bb56ca9f380be35b8efe0c04 0x19dacbf83c5de6658e14cbf7bcae5c15eca2eedecf1c66fbca928e4d351bea0f 0x000000000000000000000000f44058ffe3b8e3a6344e95a7dba8929d5b94bae2 0x4141414141494948490000000000000000000000000000000000000000000000 +383519 0x5067247f2214dca445bfb213277b5f19711e309f 0x6e7287b110b0d2f738952766cb4d4281ce49164b34e66493ebaf76c6c75c0adf +383630 0x513d9cfdf8c3f7c08006a4828e9319bafff2e556 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +383760 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +383802 0x04a163c9e3cadc6341ac0340403b42c83e384832 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +383815 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +383815 0xce4484b6d988a27ec9da967f84320c89194dd56b 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +383844 0x285b28d0c11c5bd3a039f3c26c887e2f8f177dc6 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +383852 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +383852 0xbf871ee17553ca56382a0dda5256760a0a979e62 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +383859 0xbf871ee17553ca56382a0dda5256760a0a979e62 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +383859 0xbf871ee17553ca56382a0dda5256760a0a979e62 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +383864 0xbf871ee17553ca56382a0dda5256760a0a979e62 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +383864 0xbf871ee17553ca56382a0dda5256760a0a979e62 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +383968 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +383968 0xf01d37496e1ad7f30bdc17f0dd55b7b19e53f767 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +383973 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +384127 0xad8d3a5d2d92eb14bb56ca9f380be35b8efe0c04 0x19dacbf83c5de6658e14cbf7bcae5c15eca2eedecf1c66fbca928e4d351bea0f 0x000000000000000000000000f44058ffe3b8e3a6344e95a7dba8929d5b94bae2 0x4141414141494948490000000000000000000000000000000000000000000000 +384138 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384149 0x285b28d0c11c5bd3a039f3c26c887e2f8f177dc6 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384173 0x285b28d0c11c5bd3a039f3c26c887e2f8f177dc6 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +384173 0x81e4c09f8d140521e2265b42d99fc2fb868a5b14 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384301 0x03131e9dc0d42f57c92c3ae39e79a9abac75d9bb 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384422 0x4e96c7985c2f260ae9fdd12fd7f78364f16af2ce 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384506 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384511 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384546 0xad8d3a5d2d92eb14bb56ca9f380be35b8efe0c04 0x19dacbf83c5de6658e14cbf7bcae5c15eca2eedecf1c66fbca928e4d351bea0f 0x000000000000000000000000f44058ffe3b8e3a6344e95a7dba8929d5b94bae2 0x4141414141494948490000000000000000000000000000000000000000000000 +384771 0xac4df82fe37ea2187bc8c011a23d743b4f39019a 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384825 0xac4df82fe37ea2187bc8c011a23d743b4f39019a 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +384861 0x9dfb24cf9ef6b885a7d130b5a92002985954b8e6 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384917 0x4e96c7985c2f260ae9fdd12fd7f78364f16af2ce 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384923 0xe291a9e17fd310b860f665dbdd8375144bdd6ecd 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +384965 0xc833e49ac9d0315778d616cbb583a8b1b3bf2d73 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +385067 0x3a360d9e2919714547623e4bc9504242b816d2d8 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +385073 0x3a360d9e2919714547623e4bc9504242b816d2d8 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +385356 0xe291a9e17fd310b860f665dbdd8375144bdd6ecd 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +385356 0xc833e49ac9d0315778d616cbb583a8b1b3bf2d73 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +386571 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +386620 0xdcf421d093428b096ca501a7cd1a740855a7976f +386736 0xa8637b2df8ca339818314b7def756ed19ae4d5e3 0x722f20d265a4f5c6387c6ce92203442cdcb6d30b5e188f3649f0d5cbdf9d87fb 0x0000000000000000000000000000000000000000000000000000000000000000 +386786 0xa8637b2df8ca339818314b7def756ed19ae4d5e3 0x722f20d265a4f5c6387c6ce92203442cdcb6d30b5e188f3649f0d5cbdf9d87fb 0x0000000000000000000000000000000000000000000000000000000000000001 +386795 0xa8637b2df8ca339818314b7def756ed19ae4d5e3 0x722f20d265a4f5c6387c6ce92203442cdcb6d30b5e188f3649f0d5cbdf9d87fb 0x0000000000000000000000000000000000000000000000000000000000000002 +386804 0xa8637b2df8ca339818314b7def756ed19ae4d5e3 0x722f20d265a4f5c6387c6ce92203442cdcb6d30b5e188f3649f0d5cbdf9d87fb 0x0000000000000000000000000000000000000000000000000000000000000003 +386812 0xa8637b2df8ca339818314b7def756ed19ae4d5e3 0x722f20d265a4f5c6387c6ce92203442cdcb6d30b5e188f3649f0d5cbdf9d87fb 0x0000000000000000000000000000000000000000000000000000000000000004 +386818 0xa8637b2df8ca339818314b7def756ed19ae4d5e3 0x722f20d265a4f5c6387c6ce92203442cdcb6d30b5e188f3649f0d5cbdf9d87fb 0x0000000000000000000000000000000000000000000000000000000000000005 +386899 0xa8637b2df8ca339818314b7def756ed19ae4d5e3 0x722f20d265a4f5c6387c6ce92203442cdcb6d30b5e188f3649f0d5cbdf9d87fb 0x0000000000000000000000000000000000000000000000000000000000000006 +386939 0x523c43c44671e34c1e7a9a619420b191fb009db1 0x722f20d265a4f5c6387c6ce92203442cdcb6d30b5e188f3649f0d5cbdf9d87fb 0x0000000000000000000000000000000000000000000000000000000000000000 +386945 0x7ff1fa4c4bb95760dda000b5856bc22db681e989 0x0000000000000000000000000000000000000000000000000000000000000000 +386975 0xc48d9595221e591bf7a785591f928b6df08fee7a 0x0000000000000000000000000000000000000000000000000000000000000000 +387011 0x07f1d608c18dc12e6ee4487be4d01571315dbef1 0x0000000000000000000000000000000000000000000000000000000000000000 +387014 0x07f1d608c18dc12e6ee4487be4d01571315dbef1 0x0000000000000000000000000000000000000000000000000000000000000001 +387016 0xa72cd306bd6bc58922dcfed48cb1474f323860a9 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387032 0x07f1d608c18dc12e6ee4487be4d01571315dbef1 0x0000000000000000000000000000000000000000000000000000000000000002 +387044 0x91b876c8614495fb9272a95edecc92938e5e2da6 0x0000000000000000000000000000000000000000000000000000000000000000 +387045 0xa72cd306bd6bc58922dcfed48cb1474f323860a9 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387206 0x680a79579b69df391a4d23a7ba219b4d020736dc 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387225 0x680a79579b69df391a4d23a7ba219b4d020736dc 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387241 0x680a79579b69df391a4d23a7ba219b4d020736dc 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387276 0x680a79579b69df391a4d23a7ba219b4d020736dc 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +387276 0x4b94fb373ec3a87f79f6de32ad730806020c94f1 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387284 0x680a79579b69df391a4d23a7ba219b4d020736dc 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +387365 0x72c39a1286deaffbc3058cea4f9598bf0f2f6cf6 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387615 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387627 0x2a31114378a3093d29aa387bfe3829d9f1f4c2a8 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387641 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +387648 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387654 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +387654 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +387658 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +387658 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +387683 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +387688 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +387688 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +387690 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +387690 0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +387761 0x97e58c7d37cba1a1e2ecbb2a5b23f8d127b6892d 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +388108 0x33921ef3eeffb23d68802e43e8110ab6c2fff774 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +388111 0xbec795614eda3b5ccd2e32070b4ace745ce801c4 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +388150 0xbec795614eda3b5ccd2e32070b4ace745ce801c4 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +388246 0xed6523382d41982604b845e5b94dd7fa0060198d 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +388285 0x329e2382db65ef312ca68a6c8ef549e68d051e06 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +388296 0xed6523382d41982604b845e5b94dd7fa0060198d 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +388516 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +388860 0xa36dcbd8877c08dc245ca08577368ef87a0c917e 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +388893 0xa36dcbd8877c08dc245ca08577368ef87a0c917e 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +388893 0xf2d850b176ddf0b6c1411d68ef96d2d8b7b0b480 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +388894 0xa36dcbd8877c08dc245ca08577368ef87a0c917e 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +388907 0xbda7aeb6d2002efe360b6467275ef01e77d15497 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +388907 0x2caa3e6931413fba516a377a43cadd94e197bbfa 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +388909 0x2caa3e6931413fba516a377a43cadd94e197bbfa 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +388912 0x2caa3e6931413fba516a377a43cadd94e197bbfa 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +388912 0x2caa3e6931413fba516a377a43cadd94e197bbfa 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +388918 0x2caa3e6931413fba516a377a43cadd94e197bbfa 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +388918 0x2caa3e6931413fba516a377a43cadd94e197bbfa 0xe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a +388923 0xa36dcbd8877c08dc245ca08577368ef87a0c917e 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +388923 0x2caa3e6931413fba516a377a43cadd94e197bbfa 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +388940 0xa36dcbd8877c08dc245ca08577368ef87a0c917e 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +388971 0x2a31114378a3093d29aa387bfe3829d9f1f4c2a8 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +388990 0x892140413344e49d9eaf54db38126d973fa167f6 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +389012 0x892140413344e49d9eaf54db38126d973fa167f6 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +389158 0x892140413344e49d9eaf54db38126d973fa167f6 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +389206 0xe358b3b9f29c67cb810c5184e6fde27d66ce036c 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +389238 0x72c39a1286deaffbc3058cea4f9598bf0f2f6cf6 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +389277 0x534c5a8c34ad4e150581c50ded1bbfa5f22b1800 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +389292 0xcab01dedaa9e87d03e5eff6dedab9ad98298ccc6 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +389301 0xcab01dedaa9e87d03e5eff6dedab9ad98298ccc6 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +389301 0xcab01dedaa9e87d03e5eff6dedab9ad98298ccc6 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +389309 0xcab01dedaa9e87d03e5eff6dedab9ad98298ccc6 0xc7fb647e59b18047309aa15aad418e5d7ca96d173ad704f1031a2c3d7591734b +389324 0xcab01dedaa9e87d03e5eff6dedab9ad98298ccc6 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +389324 0x72c39a1286deaffbc3058cea4f9598bf0f2f6cf6 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +389328 0x72c39a1286deaffbc3058cea4f9598bf0f2f6cf6 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +389343 0xcab01dedaa9e87d03e5eff6dedab9ad98298ccc6 0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda +389343 0xcab01dedaa9e87d03e5eff6dedab9ad98298ccc6 0x1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf32 +390001 0xecc72aac2791ee973bf607781a33a341b41e58c0 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +390004 0xecc72aac2791ee973bf607781a33a341b41e58c0 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +390024 0xd5babb9f28a9e7c78735c9c955d5626159f1be70 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +390042 0xd5babb9f28a9e7c78735c9c955d5626159f1be70 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +390236 0x54dcd97a77d12fb42a9ef839a3cdba0c1e92841a 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +390306 0xecc72aac2791ee973bf607781a33a341b41e58c0 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +390867 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +391685 0x5067247f2214dca445bfb213277b5f19711e309f 0x6e7287b110b0d2f738952766cb4d4281ce49164b34e66493ebaf76c6c75c0adf +391690 0x5067247f2214dca445bfb213277b5f19711e309f 0x6e7287b110b0d2f738952766cb4d4281ce49164b34e66493ebaf76c6c75c0adf +391691 0x5067247f2214dca445bfb213277b5f19711e309f 0x6e7287b110b0d2f738952766cb4d4281ce49164b34e66493ebaf76c6c75c0adf +391697 0xe358b3b9f29c67cb810c5184e6fde27d66ce036c 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +391713 0x534c5a8c34ad4e150581c50ded1bbfa5f22b1800 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +391849 0x534c5a8c34ad4e150581c50ded1bbfa5f22b1800 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +392002 0x81e4c09f8d140521e2265b42d99fc2fb868a5b14 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +392097 0xcab01dedaa9e87d03e5eff6dedab9ad98298ccc6 0xc7fb647e59b18047309aa15aad418e5d7ca96d173ad704f1031a2c3d7591734b +392104 0xfe8ad7dd2f564a877cc23feea6c0a9cc2e783715 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +392110 0xa076155806214a73f37f5fcd8025036d92f6a3fb +392294 0xac9560da030bc57c70c90274d8ffe4ba6aea1846 0x0000000000000000000000000000000000000000000000000000000000000000 +392697 0xc4395759e26469baa0e6421bdc1d0232c6f4b6c3 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +392960 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xd4665e3049283582ba6f9eba07a5b3e12dab49e02da99e8927a47af5d134bea5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +392970 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xd4665e3049283582ba6f9eba07a5b3e12dab49e02da99e8927a47af5d134bea5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +392990 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +393302 0x8ec0d0bbce4349e2d34586e2de392caa73532d3f 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +393370 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +393752 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x00000000000000000000000076b0f6b32c66c317699067f2d938bcf669f380ce +393752 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x00000000000000000000000076b0f6b32c66c317699067f2d938bcf669f380ce +394354 0xcab01dedaa9e87d03e5eff6dedab9ad98298ccc6 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +394389 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394389 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394390 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394390 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394390 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394391 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394393 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394393 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394394 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394395 0x6466e3c6157ba0724234f8a09c77ac08fff8828c 0xadec52fcd1408589179b85e44b434374db078b4eaf793e7d1a1bb0ae4ecfeee5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394426 0xdb30622d51e8d6221f0b1cbde57d4734387d7ca1 0xd4665e3049283582ba6f9eba07a5b3e12dab49e02da99e8927a47af5d134bea5 0x00000000000000000000000016893e10b99a59afd2c60331e0b49241d4d4d7cc +394800 0x7011f3edc7fa43c81440f9f43a6458174113b162 0x66d0ee9ee580464eb06bb7adef164c593ad3173da5b9937511307bb4646d392e 0x0000000000000000000000000000000000000000000000000000000000000075 +395595 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000d1f35f7250a922150c0e879eaf0cb5f0f7dd47c3 +395595 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000d1f35f7250a922150c0e879eaf0cb5f0f7dd47c3 +395969 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +396348 0xc4395759e26469baa0e6421bdc1d0232c6f4b6c3 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +397108 0xb372018f3be9e171df0581136b59d2faf73a7d5d 0xff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9 +397588 0xb372018f3be9e171df0581136b59d2faf73a7d5d 0xff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9 +397591 0xb372018f3be9e171df0581136b59d2faf73a7d5d 0xff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9 +398412 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x39d732521214059f57de4c0f92879304394ef7c5e530a8708b7113a42f9f0878 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +398412 0xc7696b27830dd8aa4823a1cba8440c27c36adec4 0x44bbf497379e88194e67c38a8b2e628ef3803579306f3fd2177ce81afb3d743f 0x000000000000000000000000a2792b9f27a466a635649f551a4109a179b00fbf +398456 0xfadd0c5d206310344a31711da36ac89a7baeb388 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +398477 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +398679 0xfa15b8c872f533cd40abfd055507f2907bcf1581 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +398968 0xe82f5f7db7bf9bad426505c654e8d13b609f527c 0x16cdf1707799c6655baac6e210f52b94b7cec08adcaf9ede7dfe8649da926146 +398972 0x6f7ff1690f64973fffc848f5cf101b446acb1c27 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +399058 0x6f7ff1690f64973fffc848f5cf101b446acb1c27 0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004 +399804 0xc4395759e26469baa0e6421bdc1d0232c6f4b6c3 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c +399849 0xb372018f3be9e171df0581136b59d2faf73a7d5d 0xff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9 diff --git a/ethcore/src/chainfilter/mod.rs b/ethcore/src/chainfilter/mod.rs new file mode 100644 index 000000000..d85fc20f9 --- /dev/null +++ b/ethcore/src/chainfilter/mod.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 . + +//! Multilevel blockchain bloom filter. + +mod bloomindex; +mod chainfilter; +mod indexer; + +#[cfg(test)] +mod tests; + +pub use self::bloomindex::BloomIndex; +pub use self::chainfilter::ChainFilter; +use util::hash::H2048; + +/// Types implementing this trait provide read access for bloom filters database. +pub trait FilterDataSource { + /// returns reference to log at given position if it exists + fn bloom_at_index(&self, index: &BloomIndex) -> Option; +} + diff --git a/ethcore/src/chainfilter/tests.rs b/ethcore/src/chainfilter/tests.rs new file mode 100644 index 000000000..7dac29f11 --- /dev/null +++ b/ethcore/src/chainfilter/tests.rs @@ -0,0 +1,283 @@ +// 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 std::collections::HashMap; +use std::io::{BufRead, BufReader, Read}; +use std::str::FromStr; +use util::hash::*; +use util::sha3::*; +use chainfilter::{BloomIndex, FilterDataSource, ChainFilter}; + +/// In memory cache for blooms. +/// +/// Stores all blooms in HashMap, which indexes them by `BloomIndex`. +pub struct MemoryCache { + blooms: HashMap, +} + +impl Default for MemoryCache { + fn default() -> Self { + MemoryCache::new() + } +} + +impl MemoryCache { + /// Default constructor for MemoryCache + pub fn new() -> Self { + MemoryCache { blooms: HashMap::new() } + } + + /// inserts all blooms into cache + /// + /// if bloom at given index already exists, overwrites it + pub fn insert_blooms(&mut self, blooms: HashMap) { + self.blooms.extend(blooms); + } +} + +impl FilterDataSource for MemoryCache { + fn bloom_at_index(&self, index: &BloomIndex) -> Option { + self.blooms.get(index).cloned() + } +} + +fn to_bloom(hashable: &T) -> H2048 where T: Hashable { + let mut bloom = H2048::new(); + bloom.shift_bloomed(&hashable.sha3()); + bloom +} + +#[test] +fn test_topic_basic_search() { + let index_size = 16; + let bloom_levels = 3; + + let mut cache = MemoryCache::new(); + let topic = H256::from_str("8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba").unwrap(); + + let modified_blooms = { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let block_number = 23; + filter.add_bloom(&to_bloom(&topic), block_number) + }; + + // number of modified blooms should always be equal number of levels + assert_eq!(modified_blooms.len(), bloom_levels as usize); + cache.insert_blooms(modified_blooms); + + { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let blocks = filter.blocks_with_bloom(&to_bloom(&topic), 0, 100); + assert_eq!(blocks.len(), 1); + assert_eq!(blocks[0], 23); + } + + { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let blocks = filter.blocks_with_bloom(&to_bloom(&topic), 0, 22); + assert_eq!(blocks.len(), 0); + } + + { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let blocks = filter.blocks_with_bloom(&to_bloom(&topic), 23, 23); + assert_eq!(blocks.len(), 1); + assert_eq!(blocks[0], 23); + } + + { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let blocks = filter.blocks_with_bloom(&to_bloom(&topic), 24, 100); + assert_eq!(blocks.len(), 0); + } +} + +#[test] +fn test_reset_chain_head_simple() { + let index_size = 16; + let bloom_levels = 3; + + let mut cache = MemoryCache::new(); + let topic_0 = H256::from_str("8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba").unwrap(); + let topic_1 = H256::from_str("8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dbb").unwrap(); + let topic_2 = H256::from_str("8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dbc").unwrap(); + let topic_3 = H256::from_str("8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dbd").unwrap(); + let topic_4 = H256::from_str("8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dbe").unwrap(); + let topic_5 = H256::from_str("8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dbf").unwrap(); + + let modified_blooms_0 = { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let block_number = 14; + filter.add_bloom(&to_bloom(&topic_0), block_number) + }; + + cache.insert_blooms(modified_blooms_0); + + let modified_blooms_1 = { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let block_number = 15; + filter.add_bloom(&to_bloom(&topic_1), block_number) + }; + + cache.insert_blooms(modified_blooms_1); + + let modified_blooms_2 = { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let block_number = 16; + filter.add_bloom(&to_bloom(&topic_2), block_number) + }; + + cache.insert_blooms(modified_blooms_2); + + let modified_blooms_3 = { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let block_number = 17; + filter.add_bloom(&to_bloom(&topic_3), block_number) + }; + + cache.insert_blooms(modified_blooms_3); + + + let reset_modified_blooms = { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + filter.reset_chain_head(&[to_bloom(&topic_4), to_bloom(&topic_5)], 15, 17) + }; + + cache.insert_blooms(reset_modified_blooms); + + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + assert_eq!(filter.blocks_with_bloom(&to_bloom(&topic_0), 0, 100), vec![14]); + assert_eq!(filter.blocks_with_bloom(&to_bloom(&topic_1), 0, 100), vec![]); + assert_eq!(filter.blocks_with_bloom(&to_bloom(&topic_2), 0, 100), vec![]); + assert_eq!(filter.blocks_with_bloom(&to_bloom(&topic_3), 0, 100), vec![]); + assert_eq!(filter.blocks_with_bloom(&to_bloom(&topic_4), 0, 100), vec![15]); + assert_eq!(filter.blocks_with_bloom(&to_bloom(&topic_5), 0, 100), vec![16]); +} + +fn for_each_bloom(bytes: &[u8], mut f: F) where F: FnMut(usize, &H2048) { + let mut reader = BufReader::new(bytes); + let mut line = String::new(); + while reader.read_line(&mut line).unwrap() > 0 { + { + let mut number_bytes = vec![]; + let mut bloom_bytes = [0; 512]; + + let mut line_reader = BufReader::new(line.as_ref() as &[u8]); + line_reader.read_until(b' ', &mut number_bytes).unwrap(); + line_reader.consume(2); + line_reader.read_exact(&mut bloom_bytes).unwrap(); + + let number = String::from_utf8(number_bytes).map(|s| s[..s.len() -1].to_owned()).unwrap().parse::().unwrap(); + let bloom = H2048::from_str(&String::from_utf8(bloom_bytes.to_vec()).unwrap()).unwrap(); + f(number, &bloom); + } + line.clear(); + } +} + +fn for_each_log(bytes: &[u8], mut f: F) where F: FnMut(usize, &Address, &[H256]) { + let mut reader = BufReader::new(bytes); + let mut line = String::new(); + while reader.read_line(&mut line).unwrap() > 0 { + { + let mut number_bytes = vec![]; + let mut address_bytes = [0;42]; + let mut topic = [0;66]; + let mut topics_bytes = vec![]; + + let mut line_reader = BufReader::new(line.as_ref() as &[u8]); + line_reader.read_until(b' ', &mut number_bytes).unwrap(); + line_reader.read_exact(&mut address_bytes).unwrap(); + line_reader.consume(1); + while let Ok(_) = line_reader.read_exact(&mut topic) { + line_reader.consume(1); + topics_bytes.push(topic.to_vec()); + } + + let number = String::from_utf8(number_bytes).map(|s| s[..s.len() -1].to_owned()).unwrap().parse::().unwrap(); + let address = Address::from_str(&String::from_utf8(address_bytes.to_vec()).map(|a| a[2..].to_owned()).unwrap()).unwrap(); + let topics: Vec = topics_bytes + .into_iter() + .map(|t| H256::from_str(&String::from_utf8(t).map(|t| t[2..].to_owned()).unwrap()).unwrap()) + .collect(); + f(number, &address, &topics); + } + line.clear(); + } +} + +// tests chain filter on real data between blocks 300_000 and 400_000 +#[test] +fn test_chainfilter_real_data_short_searches() { + let index_size = 16; + let bloom_levels = 3; + + let mut cache = MemoryCache::new(); + + for_each_bloom(include_bytes!("blooms.txt"), | block_number, bloom | { + let modified_blooms = { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + filter.add_bloom(bloom, block_number) + }; + + // number of modified blooms should always be equal number of levels + assert_eq!(modified_blooms.len(), bloom_levels as usize); + cache.insert_blooms(modified_blooms); + }); + + for_each_log(include_bytes!("logs.txt"), | block_number, address, topics | { + println!("block_number: {:?}", block_number); + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let blocks = filter.blocks_with_bloom(&to_bloom(address), block_number, block_number); + assert_eq!(blocks.len(), 1); + for (i, topic) in topics.iter().enumerate() { + println!("topic: {:?}", i); + let blocks = filter.blocks_with_bloom(&to_bloom(topic), block_number, block_number); + assert_eq!(blocks.len(), 1); + } + }); +} + +// tests chain filter on real data between blocks 300_000 and 400_000 +#[test] +fn test_chainfilter_real_data_single_search() { + let index_size = 16; + let bloom_levels = 3; + + let mut cache = MemoryCache::new(); + + for_each_bloom(include_bytes!("blooms.txt"), | block_number, bloom | { + let modified_blooms = { + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + filter.add_bloom(bloom, block_number) + }; + + // number of modified blooms should always be equal number of levels + assert_eq!(modified_blooms.len(), bloom_levels as usize); + cache.insert_blooms(modified_blooms); + }); + + let address = Address::from_str("c4395759e26469baa0e6421bdc1d0232c6f4b6c3").unwrap(); + let filter = ChainFilter::new(&cache, index_size, bloom_levels); + let blocks = filter.blocks_with_bloom(&to_bloom(&address), 300_000, 400_000); + // bloom may return more blocks, but our log density is low, so it should be fine + assert_eq!(blocks.len(), 3); + assert_eq!(blocks[0], 392697); + assert_eq!(blocks[1], 396348); + assert_eq!(blocks[2], 399804); +} + + diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs deleted file mode 100644 index 09f7417e8..000000000 --- a/ethcore/src/client.rs +++ /dev/null @@ -1,464 +0,0 @@ -// 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 database client. - -use util::*; -use util::panics::*; -use rocksdb::{Options, DB, DBCompactionStyle}; -use blockchain::{BlockChain, BlockProvider, CacheSize}; -use views::BlockView; -use error::*; -use header::BlockNumber; -use state::State; -use spec::Spec; -use engine::Engine; -use views::HeaderView; -use block_queue::{BlockQueue, BlockQueueInfo}; -use service::{NetSyncMessage, SyncMessage}; -use env_info::LastHashes; -use verification::*; -use block::*; -use transaction::LocalizedTransaction; -use extras::TransactionAddress; -pub use blockchain::TreeRoute; - -/// Uniquely identifies block. -#[derive(Debug, PartialEq, Clone)] -pub enum BlockId { - /// Block's sha3. - /// Querying by hash is always faster. - Hash(H256), - /// Block number within canon blockchain. - Number(BlockNumber), - /// Earliest block (genesis). - Earliest, - /// Latest mined block. - Latest -} - -/// Uniquely identifies transaction. -#[derive(Debug, PartialEq, Clone)] -pub enum TransactionId { - /// Transaction's sha3. - Hash(H256), - /// Block id and transaction index within this block. - /// Querying by block position is always faster. - Location(BlockId, usize) -} - -/// General block status -#[derive(Debug, Eq, PartialEq)] -pub enum BlockStatus { - /// Part of the blockchain. - InChain, - /// Queued for import. - Queued, - /// Known as bad. - Bad, - /// Unknown. - Unknown, -} - -/// Information about the blockchain gthered together. -#[derive(Debug)] -pub struct BlockChainInfo { - /// Blockchain difficulty. - pub total_difficulty: U256, - /// Block queue difficulty. - pub pending_total_difficulty: U256, - /// Genesis block hash. - pub genesis_hash: H256, - /// Best blockchain block hash. - pub best_block_hash: H256, - /// Best blockchain block number. - pub best_block_number: BlockNumber -} - -impl fmt::Display for BlockChainInfo { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "#{}.{}", self.best_block_number, self.best_block_hash) - } -} - -/// Blockchain database client. Owns and manages a blockchain and a block queue. -pub trait BlockChainClient : Sync + Send { - /// Get raw block header data by block id. - fn block_header(&self, id: BlockId) -> Option; - - /// Get raw block body data by block id. - /// Block body is an RLP list of two items: uncles and transactions. - fn block_body(&self, id: BlockId) -> Option; - - /// Get raw block data by block header hash. - fn block(&self, id: BlockId) -> Option; - - /// Get block status by block header hash. - fn block_status(&self, id: BlockId) -> BlockStatus; - - /// Get block total difficulty. - fn block_total_difficulty(&self, id: BlockId) -> Option; - - /// Get address code. - fn code(&self, address: &Address) -> Option; - - /// Get transaction with given hash. - fn transaction(&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; - - /// Get latest state node - fn state_data(&self, hash: &H256) -> Option; - - /// Get raw block receipts data by block header hash. - fn block_receipts(&self, hash: &H256) -> Option; - - /// Import a block into the blockchain. - fn import_block(&self, bytes: Bytes) -> ImportResult; - - /// Get block queue information. - fn queue_info(&self) -> BlockQueueInfo; - - /// Clear block queue and abort all import activity. - fn clear_queue(&self); - - /// Get blockchain information. - fn chain_info(&self) -> BlockChainInfo; - - /// Get the best block header. - fn best_block_header(&self) -> Bytes { - self.block_header(BlockId::Hash(self.chain_info().best_block_hash)).unwrap() - } -} - -#[derive(Default, Clone, Debug, Eq, PartialEq)] -/// Report on the status of a client. -pub struct ClientReport { - /// How many blocks have been imported so far. - pub blocks_imported: usize, - /// How many transactions have been applied so far. - pub transactions_applied: usize, - /// How much gas has been processed so far. - pub gas_processed: U256, -} - -impl ClientReport { - /// Alter internal reporting to reflect the additional `block` has been processed. - pub fn accrue_block(&mut self, block: &PreVerifiedBlock) { - self.blocks_imported += 1; - self.transactions_applied += block.transactions.len(); - self.gas_processed += block.header.gas_used; - } -} - -/// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue. -/// Call `import_block()` to import a block asynchronously; `flush_queue()` flushes the queue. -pub struct Client { - chain: Arc>, - engine: Arc>, - state_db: Mutex, - block_queue: RwLock, - report: RwLock, - import_lock: Mutex<()>, - panic_handler: Arc, -} - -const HISTORY: u64 = 1000; -const CLIENT_DB_VER_STR: &'static str = "2.1"; - -impl Client { - /// Create a new client with given spec and DB path. - pub fn new(spec: Spec, path: &Path, message_channel: IoChannel ) -> Result, Error> { - let mut dir = path.to_path_buf(); - dir.push(H64::from(spec.genesis_header().hash()).hex()); - //TODO: sec/fat: pruned/full versioning - dir.push(format!("v{}-sec-pruned", CLIENT_DB_VER_STR)); - let path = dir.as_path(); - let gb = spec.genesis_block(); - let chain = Arc::new(RwLock::new(BlockChain::new(&gb, path))); - let mut opts = Options::new(); - opts.set_max_open_files(256); - opts.create_if_missing(true); - opts.set_use_fsync(false); - opts.set_compaction_style(DBCompactionStyle::DBUniversalCompaction); - /* - opts.set_bytes_per_sync(8388608); - opts.set_disable_data_sync(false); - opts.set_block_cache_size_mb(1024); - opts.set_table_cache_num_shard_bits(6); - opts.set_max_write_buffer_number(32); - opts.set_write_buffer_size(536870912); - opts.set_target_file_size_base(1073741824); - opts.set_min_write_buffer_number_to_merge(4); - opts.set_level_zero_stop_writes_trigger(2000); - opts.set_level_zero_slowdown_writes_trigger(0); - opts.set_compaction_style(DBUniversalCompaction); - opts.set_max_background_compactions(4); - opts.set_max_background_flushes(4); - opts.set_filter_deletes(false); - opts.set_disable_auto_compactions(false);*/ - - let mut state_path = path.to_path_buf(); - state_path.push("state"); - let db = Arc::new(DB::open(&opts, state_path.to_str().unwrap()).unwrap()); - - let engine = Arc::new(try!(spec.to_engine())); - let mut state_db = JournalDB::new_with_arc(db.clone()); - if state_db.is_empty() && engine.spec().ensure_db_good(&mut state_db) { - state_db.commit(0, &engine.spec().genesis_header().hash(), None).expect("Error commiting genesis state to state DB"); - } - - let block_queue = BlockQueue::new(engine.clone(), message_channel); - let panic_handler = PanicHandler::new_in_arc(); - panic_handler.forward_from(&block_queue); - - Ok(Arc::new(Client { - chain: chain, - engine: engine, - state_db: Mutex::new(state_db), - block_queue: RwLock::new(block_queue), - report: RwLock::new(Default::default()), - import_lock: Mutex::new(()), - panic_handler: panic_handler - })) - } - - /// Flush the block import queue. - pub fn flush_queue(&self) { - self.block_queue.write().unwrap().flush(); - } - - /// This is triggered by a message coming from a block queue when the block is ready for insertion - pub fn import_verified_blocks(&self, io: &IoChannel) -> usize { - let mut ret = 0; - let mut bad = HashSet::new(); - let _import_lock = self.import_lock.lock(); - let blocks = self.block_queue.write().unwrap().drain(128); - let mut good_blocks = Vec::with_capacity(128); - for block in blocks { - if bad.contains(&block.header.parent_hash) { - self.block_queue.write().unwrap().mark_as_bad(&block.header.hash()); - bad.insert(block.header.hash()); - continue; - } - - let header = &block.header; - if let Err(e) = verify_block_family(&header, &block.bytes, self.engine.deref().deref(), self.chain.read().unwrap().deref()) { - warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); - self.block_queue.write().unwrap().mark_as_bad(&header.hash()); - bad.insert(block.header.hash()); - break; - }; - let parent = match self.chain.read().unwrap().block_header(&header.parent_hash) { - Some(p) => p, - None => { - warn!(target: "client", "Block import failed for #{} ({}): Parent not found ({}) ", header.number(), header.hash(), header.parent_hash); - self.block_queue.write().unwrap().mark_as_bad(&header.hash()); - bad.insert(block.header.hash()); - break; - }, - }; - // build last hashes - let mut last_hashes = LastHashes::new(); - last_hashes.resize(256, H256::new()); - last_hashes[0] = header.parent_hash.clone(); - for i in 0..255 { - match self.chain.read().unwrap().block_details(&last_hashes[i]) { - Some(details) => { - last_hashes[i + 1] = details.parent.clone(); - }, - None => break, - } - } - - let db = self.state_db.lock().unwrap().clone(); - let result = match enact_verified(&block, self.engine.deref().deref(), db, &parent, &last_hashes) { - Ok(b) => b, - Err(e) => { - warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); - bad.insert(block.header.hash()); - self.block_queue.write().unwrap().mark_as_bad(&header.hash()); - break; - } - }; - if let Err(e) = verify_block_final(&header, result.block().header()) { - warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); - self.block_queue.write().unwrap().mark_as_bad(&header.hash()); - break; - } - - good_blocks.push(header.hash().clone()); - - self.chain.write().unwrap().insert_block(&block.bytes); //TODO: err here? - let ancient = if header.number() >= HISTORY { Some(header.number() - HISTORY) } else { None }; - match result.drain().commit(header.number(), &header.hash(), ancient.map(|n|(n, self.chain.read().unwrap().block_hash(n).unwrap()))) { - Ok(_) => (), - Err(e) => { - warn!(target: "client", "State DB commit failed: {:?}", e); - break; - } - } - self.report.write().unwrap().accrue_block(&block); - trace!(target: "client", "Imported #{} ({})", header.number(), header.hash()); - ret += 1; - } - self.block_queue.write().unwrap().mark_as_good(&good_blocks); - if !good_blocks.is_empty() && self.block_queue.read().unwrap().queue_info().is_empty() { - io.send(NetworkIoMessage::User(SyncMessage::BlockVerified)).unwrap(); - } - ret - } - - /// Get a copy of the best block's state. - pub fn state(&self) -> State { - State::from_existing(self.state_db.lock().unwrap().clone(), HeaderView::new(&self.best_block_header()).state_root(), self.engine.account_start_nonce()) - } - - /// Get info on the cache. - pub fn cache_info(&self) -> CacheSize { - self.chain.read().unwrap().cache_size() - } - - /// Get the report. - pub fn report(&self) -> ClientReport { - self.report.read().unwrap().clone() - } - - /// Tick the client. - pub fn tick(&self) { - self.chain.read().unwrap().collect_garbage(); - } - - /// Set up the cache behaviour. - pub fn configure_cache(&self, pref_cache_size: usize, max_cache_size: usize) { - self.chain.write().unwrap().configure_cache(pref_cache_size, max_cache_size); - } - - fn block_hash(chain: &BlockChain, id: BlockId) -> Option { - match id { - BlockId::Hash(hash) => Some(hash), - BlockId::Number(number) => chain.block_hash(number), - BlockId::Earliest => chain.block_hash(0), - BlockId::Latest => Some(chain.best_block_hash()) - } - } -} - -impl BlockChainClient for Client { - fn block_header(&self, id: BlockId) -> Option { - let chain = self.chain.read().unwrap(); - Self::block_hash(&chain, id).and_then(|hash| chain.block(&hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec())) - } - - fn block_body(&self, id: BlockId) -> Option { - let chain = self.chain.read().unwrap(); - Self::block_hash(&chain, id).and_then(|hash| { - chain.block(&hash).map(|bytes| { - let rlp = Rlp::new(&bytes); - let mut body = RlpStream::new_list(2); - body.append_raw(rlp.at(1).as_raw(), 1); - body.append_raw(rlp.at(2).as_raw(), 1); - body.out() - }) - }) - } - - fn block(&self, id: BlockId) -> Option { - let chain = self.chain.read().unwrap(); - Self::block_hash(&chain, id).and_then(|hash| { - chain.block(&hash) - }) - } - - fn block_status(&self, id: BlockId) -> BlockStatus { - let chain = self.chain.read().unwrap(); - match Self::block_hash(&chain, id) { - Some(ref hash) if chain.is_known(hash) => BlockStatus::InChain, - Some(hash) => self.block_queue.read().unwrap().block_status(&hash), - None => BlockStatus::Unknown - } - } - - fn block_total_difficulty(&self, id: BlockId) -> Option { - let chain = self.chain.read().unwrap(); - Self::block_hash(&chain, id).and_then(|hash| chain.block_details(&hash)).map(|d| d.total_difficulty) - } - - fn code(&self, address: &Address) -> Option { - self.state().code(address) - } - - fn transaction(&self, id: TransactionId) -> Option { - let chain = self.chain.read().unwrap(); - match id { - TransactionId::Hash(ref hash) => chain.transaction_address(hash), - TransactionId::Location(id, index) => Self::block_hash(&chain, id).map(|hash| TransactionAddress { - block_hash: hash, - index: index - }) - }.and_then(|address| chain.transaction(&address)) - } - - fn tree_route(&self, from: &H256, to: &H256) -> Option { - self.chain.read().unwrap().tree_route(from.clone(), to.clone()) - } - - fn state_data(&self, _hash: &H256) -> Option { - unimplemented!(); - } - - fn block_receipts(&self, _hash: &H256) -> Option { - unimplemented!(); - } - - fn import_block(&self, bytes: Bytes) -> ImportResult { - let header = BlockView::new(&bytes).header(); - if self.chain.read().unwrap().is_known(&header.hash()) { - return Err(ImportError::AlreadyInChain); - } - if self.block_status(BlockId::Hash(header.parent_hash)) == BlockStatus::Unknown { - return Err(ImportError::UnknownParent); - } - self.block_queue.write().unwrap().import_block(bytes) - } - - fn queue_info(&self) -> BlockQueueInfo { - self.block_queue.read().unwrap().queue_info() - } - - fn clear_queue(&self) { - self.block_queue.write().unwrap().clear(); - } - - fn chain_info(&self) -> BlockChainInfo { - let chain = self.chain.read().unwrap(); - BlockChainInfo { - total_difficulty: chain.best_block_total_difficulty(), - pending_total_difficulty: chain.best_block_total_difficulty(), - genesis_hash: chain.genesis_hash(), - best_block_hash: chain.best_block_hash(), - best_block_number: From::from(chain.best_block_number()) - } - } -} - -impl MayPanic for Client { - fn on_panic(&self, closure: F) where F: OnPanicListener { - self.panic_handler.on_panic(closure); - } -} diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs new file mode 100644 index 000000000..61e3b4cd8 --- /dev/null +++ b/ethcore/src/client/client.rs @@ -0,0 +1,693 @@ +// 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 database client. + +use std::marker::PhantomData; +use util::*; +use util::panics::*; +use views::BlockView; +use error::*; +use header::{BlockNumber, Header}; +use state::State; +use spec::Spec; +use engine::Engine; +use views::HeaderView; +use service::{NetSyncMessage, SyncMessage}; +use env_info::LastHashes; +use verification::*; +use block::*; +use transaction::{LocalizedTransaction, SignedTransaction}; +use extras::TransactionAddress; +use filter::Filter; +use log_entry::LocalizedLogEntry; +use block_queue::{BlockQueue, BlockQueueInfo}; +use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute}; +use client::{BlockId, TransactionId, UncleId, ClientConfig, BlockChainClient}; +use env_info::EnvInfo; +use executive::{Executive, Executed}; +use receipt::LocalizedReceipt; +pub use blockchain::CacheSize as BlockChainCacheSize; + +/// General block status +#[derive(Debug, Eq, PartialEq)] +pub enum BlockStatus { + /// Part of the blockchain. + InChain, + /// Queued for import. + Queued, + /// Known as bad. + Bad, + /// Unknown. + Unknown, +} + +/// Information about the blockchain gathered together. +#[derive(Debug)] +pub struct BlockChainInfo { + /// Blockchain difficulty. + pub total_difficulty: U256, + /// Block queue difficulty. + pub pending_total_difficulty: U256, + /// Genesis block hash. + pub genesis_hash: H256, + /// Best blockchain block hash. + pub best_block_hash: H256, + /// Best blockchain block number. + pub best_block_number: BlockNumber +} + +impl fmt::Display for BlockChainInfo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "#{}.{}", self.best_block_number, self.best_block_hash) + } +} + +/// Report on the status of a client. +#[derive(Default, Clone, Debug, Eq, PartialEq)] +pub struct ClientReport { + /// How many blocks have been imported so far. + pub blocks_imported: usize, + /// How many transactions have been applied so far. + pub transactions_applied: usize, + /// How much gas has been processed so far. + pub gas_processed: U256, + /// Memory used by state DB + pub state_db_mem: usize, +} + +impl ClientReport { + /// Alter internal reporting to reflect the additional `block` has been processed. + pub fn accrue_block(&mut self, block: &PreverifiedBlock) { + self.blocks_imported += 1; + self.transactions_applied += block.transactions.len(); + self.gas_processed = self.gas_processed + block.header.gas_used; + } +} + +/// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue. +/// Call `import_block()` to import a block asynchronously; `flush_queue()` flushes the queue. +pub struct Client where V: Verifier { + chain: Arc, + engine: Arc>, + state_db: Mutex>, + block_queue: BlockQueue, + report: RwLock, + import_lock: Mutex<()>, + panic_handler: Arc, + verifier: PhantomData, +} + +const HISTORY: u64 = 1200; +// DO NOT TOUCH THIS ANY MORE UNLESS YOU REALLY KNOW WHAT YOU'RE DOING. +// Altering it will force a blanket DB update for *all* JournalDB-derived +// databases. +// Instead, add/upgrade the version string of the individual JournalDB-derived database +// of which you actually want force an upgrade. +const CLIENT_DB_VER_STR: &'static str = "5.3"; + +impl Client { + /// Create a new client with given spec and DB path. + pub fn new(config: ClientConfig, spec: Spec, path: &Path, message_channel: IoChannel ) -> Result, Error> { + Client::::new_with_verifier(config, spec, path, message_channel) + } +} + +impl Client where V: Verifier { + /// Create a new client with given spec and DB path and custom verifier. + pub fn new_with_verifier(config: ClientConfig, spec: Spec, path: &Path, message_channel: IoChannel ) -> Result>, Error> { + let mut dir = path.to_path_buf(); + dir.push(H64::from(spec.genesis_header().hash()).hex()); + //TODO: sec/fat: pruned/full versioning + // version here is a bit useless now, since it's controlled only be the pruning algo. + dir.push(format!("v{}-sec-{}", CLIENT_DB_VER_STR, config.pruning)); + let path = dir.as_path(); + let gb = spec.genesis_block(); + let chain = Arc::new(BlockChain::new(config.blockchain, &gb, path)); + let mut state_path = path.to_path_buf(); + state_path.push("state"); + + let engine = Arc::new(try!(spec.to_engine())); + let state_path_str = state_path.to_str().unwrap(); + let mut state_db = journaldb::new(state_path_str, config.pruning); + + if state_db.is_empty() && engine.spec().ensure_db_good(state_db.as_hashdb_mut()) { + state_db.commit(0, &engine.spec().genesis_header().hash(), None).expect("Error commiting genesis state to state DB"); + } + + let block_queue = BlockQueue::new(config.queue, engine.clone(), message_channel); + let panic_handler = PanicHandler::new_in_arc(); + panic_handler.forward_from(&block_queue); + + Ok(Arc::new(Client { + chain: chain, + engine: engine, + state_db: Mutex::new(state_db), + block_queue: block_queue, + report: RwLock::new(Default::default()), + import_lock: Mutex::new(()), + panic_handler: panic_handler, + verifier: PhantomData, + })) + } + + /// Flush the block import queue. + pub fn flush_queue(&self) { + self.block_queue.flush(); + } + + fn build_last_hashes(&self, parent_hash: H256) -> LastHashes { + let mut last_hashes = LastHashes::new(); + last_hashes.resize(256, H256::new()); + last_hashes[0] = parent_hash; + for i in 0..255 { + match self.chain.block_details(&last_hashes[i]) { + Some(details) => { + last_hashes[i + 1] = details.parent.clone(); + }, + None => break, + } + } + last_hashes + } + + fn check_and_close_block(&self, block: &PreverifiedBlock) -> Result { + let engine = self.engine.deref().deref(); + let header = &block.header; + + // Check the block isn't so old we won't be able to enact it. + let best_block_number = self.chain.best_block_number(); + if best_block_number >= HISTORY && header.number() <= best_block_number - HISTORY { + warn!(target: "client", "Block import failed for #{} ({})\nBlock is ancient (current best block: #{}).", header.number(), header.hash(), best_block_number); + return Err(()); + } + + // Verify Block Family + let verify_family_result = V::verify_block_family(&header, &block.bytes, engine, self.chain.deref()); + if let Err(e) = verify_family_result { + warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); + return Err(()); + }; + + // Check if Parent is in chain + let chain_has_parent = self.chain.block_header(&header.parent_hash); + if let None = chain_has_parent { + warn!(target: "client", "Block import failed for #{} ({}): Parent not found ({}) ", header.number(), header.hash(), header.parent_hash); + return Err(()); + }; + + // Enact Verified Block + let parent = chain_has_parent.unwrap(); + 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, self.chain.have_tracing(), db, &parent, last_hashes); + if let Err(e) = enact_result { + warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); + return Err(()); + }; + + // Final Verification + let closed_block = enact_result.unwrap(); + if let Err(e) = V::verify_block_final(&header, closed_block.block().header()) { + warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); + return Err(()); + } + + Ok(closed_block) + } + + fn calculate_enacted_retracted(&self, import_results: Vec) -> (Vec, Vec) { + fn map_to_vec(map: Vec<(H256, bool)>) -> Vec { + map.into_iter().map(|(k, _v)| k).collect() + } + + // In ImportRoute we get all the blocks that have been enacted and retracted by single insert. + // Because we are doing multiple inserts some of the blocks that were enacted in import `k` + // could be retracted in import `k+1`. This is why to understand if after all inserts + // the block is enacted or retracted we iterate over all routes and at the end final state + // will be in the hashmap + let map = import_results.into_iter().fold(HashMap::new(), |mut map, route| { + for hash in route.enacted { + map.insert(hash, true); + } + for hash in route.retracted { + map.insert(hash, false); + } + map + }); + + // Split to enacted retracted (using hashmap value) + let (enacted, retracted) = map.into_iter().partition(|&(_k, v)| v); + // And convert tuples to keys + (map_to_vec(enacted), map_to_vec(retracted)) + } + + /// This is triggered by a message coming from a block queue when the block is ready for insertion + pub fn import_verified_blocks(&self, io: &IoChannel) -> usize { + let max_blocks_to_import = 128; + + let mut imported_blocks = Vec::with_capacity(max_blocks_to_import); + let mut invalid_blocks = HashSet::new(); + let mut import_results = Vec::with_capacity(max_blocks_to_import); + + let _import_lock = self.import_lock.lock(); + let blocks = self.block_queue.drain(max_blocks_to_import); + + let original_best = self.chain_info().best_block_hash; + + for block in blocks { + let header = &block.header; + + if invalid_blocks.contains(&header.parent_hash) { + invalid_blocks.insert(header.hash()); + continue; + } + let closed_block = self.check_and_close_block(&block); + if let Err(_) = closed_block { + invalid_blocks.insert(header.hash()); + break; + } + imported_blocks.push(header.hash()); + + // Are we committing an era? + let ancient = if header.number() >= HISTORY { + let n = header.number() - HISTORY; + Some((n, self.chain.block_hash(n).unwrap())) + } else { + None + }; + + // Commit results + let closed_block = closed_block.unwrap(); + let receipts = closed_block.block().receipts().clone(); + closed_block.drain() + .commit(header.number(), &header.hash(), ancient) + .expect("State DB commit failed."); + + // And update the chain after commit to prevent race conditions + // (when something is in chain but you are not able to fetch details) + let route = self.chain.insert_block(&block.bytes, receipts); + import_results.push(route); + + self.report.write().unwrap().accrue_block(&block); + trace!(target: "client", "Imported #{} ({})", header.number(), header.hash()); + } + + let imported = imported_blocks.len(); + let invalid_blocks = invalid_blocks.into_iter().collect::>(); + + { + if !invalid_blocks.is_empty() { + self.block_queue.mark_as_bad(&invalid_blocks); + } + if !imported_blocks.is_empty() { + self.block_queue.mark_as_good(&imported_blocks); + } + } + + { + if !imported_blocks.is_empty() && self.block_queue.queue_info().is_empty() { + let (enacted, retracted) = self.calculate_enacted_retracted(import_results); + io.send(NetworkIoMessage::User(SyncMessage::NewChainBlocks { + imported: imported_blocks, + invalid: invalid_blocks, + enacted: enacted, + retracted: retracted, + })).unwrap(); + } + } + + { + if self.chain_info().best_block_hash != original_best { + io.send(NetworkIoMessage::User(SyncMessage::NewChainHead)).unwrap(); + } + } + + imported + } + + /// Get a copy of the best block's state. + pub fn state(&self) -> State { + State::from_existing(self.state_db.lock().unwrap().spawn(), HeaderView::new(&self.best_block_header()).state_root(), self.engine.account_start_nonce()) + } + + /// Get info on the cache. + pub fn blockchain_cache_info(&self) -> BlockChainCacheSize { + self.chain.cache_size() + } + + /// Get the report. + pub fn report(&self) -> ClientReport { + let mut report = self.report.read().unwrap().clone(); + report.state_db_mem = self.state_db.lock().unwrap().mem_used(); + report + } + + /// Tick the client. + pub fn tick(&self) { + self.chain.collect_garbage(); + self.block_queue.collect_garbage(); + } + + /// Set up the cache behaviour. + pub fn configure_cache(&self, pref_cache_size: usize, max_cache_size: usize) { + self.chain.configure_cache(pref_cache_size, max_cache_size); + } + + fn block_hash(chain: &BlockChain, id: BlockId) -> Option { + match id { + BlockId::Hash(hash) => Some(hash), + BlockId::Number(number) => chain.block_hash(number), + BlockId::Earliest => chain.block_hash(0), + BlockId::Latest => Some(chain.best_block_hash()) + } + } + + fn block_number(&self, id: BlockId) -> Option { + match id { + BlockId::Number(number) => Some(number), + BlockId::Hash(ref hash) => self.chain.block_number(hash), + BlockId::Earliest => Some(0), + 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, false) + } + + // 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<(ClosedBlock, HashSet)> { + let engine = self.engine.deref().deref(); + let h = self.chain.best_block_hash(); + + let mut b = OpenBlock::new( + engine, + false, // TODO: this will need to be parameterised once we want to do immediate mining insertion. + self.state_db.lock().unwrap().spawn(), + match self.chain.block_header(&h) { Some(ref x) => x, None => {return None} }, + self.build_last_hashes(h.clone()), + author, + gas_floor_target, + extra_data, + ); + + // Add uncles + self.chain + .find_uncle_headers(&h, engine.maximum_uncle_age()) + .unwrap() + .into_iter() + .take(engine.maximum_uncle_count()) + .foreach(|h| { + b.push_uncle(h).unwrap(); + }); + + // 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); + + 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!(target: "miner", "Sealing: number={}, hash={}, diff={}", + b.block().header().number(), + b.hash(), + b.block().header().difficulty() + ); + Some((b, invalid_transactions)) + } + + fn block_header(&self, id: BlockId) -> Option { + Self::block_hash(&self.chain, id).and_then(|hash| self.chain.block(&hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec())) + } + + fn block_body(&self, id: BlockId) -> Option { + Self::block_hash(&self.chain, id).and_then(|hash| { + self.chain.block(&hash).map(|bytes| { + let rlp = Rlp::new(&bytes); + let mut body = RlpStream::new_list(2); + body.append_raw(rlp.at(1).as_raw(), 1); + body.append_raw(rlp.at(2).as_raw(), 1); + body.out() + }) + }) + } + + fn block(&self, id: BlockId) -> Option { + Self::block_hash(&self.chain, id).and_then(|hash| { + self.chain.block(&hash) + }) + } + + fn block_status(&self, id: BlockId) -> BlockStatus { + match Self::block_hash(&self.chain, id) { + Some(ref hash) if self.chain.is_known(hash) => BlockStatus::InChain, + Some(hash) => self.block_queue.block_status(&hash), + None => BlockStatus::Unknown + } + } + + fn block_total_difficulty(&self, id: BlockId) -> Option { + Self::block_hash(&self.chain, id).and_then(|hash| self.chain.block_details(&hash)).map(|d| d.total_difficulty) + } + + fn nonce(&self, address: &Address) -> U256 { + self.state().nonce(address) + } + + fn block_hash(&self, id: BlockId) -> Option { + Self::block_hash(&self.chain, id) + } + + fn code(&self, address: &Address) -> Option { + self.state().code(address) + } + + fn balance(&self, address: &Address) -> U256 { + self.state().balance(address) + } + + fn storage_at(&self, address: &Address, position: &H256) -> H256 { + self.state().storage_at(address, position) + } + + fn transaction(&self, id: TransactionId) -> Option { + self.transaction_address(id).and_then(|address| self.chain.transaction(&address)) + } + + fn uncle(&self, id: UncleId) -> Option
{ + let index = id.1; + self.block(id.0).and_then(|block| BlockView::new(&block).uncle_at(index)) + } + + 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 { + match self.chain.is_known(from) && self.chain.is_known(to) { + true => Some(self.chain.tree_route(from.clone(), to.clone())), + false => None + } + } + + fn state_data(&self, hash: &H256) -> Option { + self.state_db.lock().unwrap().state(hash) + } + + fn block_receipts(&self, hash: &H256) -> Option { + self.chain.block_receipts(hash).map(|receipts| rlp::encode(&receipts).to_vec()) + } + + fn import_block(&self, bytes: Bytes) -> ImportResult { + { + let header = BlockView::new(&bytes).header_view(); + if self.chain.is_known(&header.sha3()) { + return Err(x!(ImportError::AlreadyInChain)); + } + if self.block_status(BlockId::Hash(header.parent_hash())) == BlockStatus::Unknown { + return Err(x!(BlockError::UnknownParent(header.parent_hash()))); + } + } + self.block_queue.import_block(bytes) + } + + fn queue_info(&self) -> BlockQueueInfo { + self.block_queue.queue_info() + } + + fn clear_queue(&self) { + self.block_queue.clear(); + } + + fn chain_info(&self) -> BlockChainInfo { + BlockChainInfo { + total_difficulty: self.chain.best_block_total_difficulty(), + pending_total_difficulty: self.chain.best_block_total_difficulty(), + genesis_hash: self.chain.genesis_hash(), + best_block_hash: self.chain.best_block_hash(), + best_block_number: From::from(self.chain.best_block_number()) + } + } + + fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockId, to_block: BlockId) -> Option> { + match (self.block_number(from_block), self.block_number(to_block)) { + (Some(from), Some(to)) => Some(self.chain.blocks_with_bloom(bloom, from, to)), + _ => None + } + } + + fn logs(&self, filter: Filter) -> Vec { + // TODO: lock blockchain only once + + let mut blocks = filter.bloom_possibilities().iter() + .filter_map(|bloom| self.blocks_with_bloom(bloom, filter.from_block.clone(), filter.to_block.clone())) + .flat_map(|m| m) + // remove duplicate elements + .collect::>() + .into_iter() + .collect::>(); + + blocks.sort(); + + blocks.into_iter() + .filter_map(|number| self.chain.block_hash(number).map(|hash| (number, hash))) + .filter_map(|(number, hash)| self.chain.block_receipts(&hash).map(|r| (number, hash, r.receipts))) + .filter_map(|(number, hash, receipts)| self.chain.block(&hash).map(|ref b| (number, hash, receipts, BlockView::new(b).transaction_hashes()))) + .flat_map(|(number, hash, receipts, hashes)| { + let mut log_index = 0; + receipts.into_iter() + .enumerate() + .flat_map(|(index, receipt)| { + log_index += receipt.logs.len(); + receipt.logs.into_iter() + .enumerate() + .filter(|tuple| filter.matches(&tuple.1)) + .map(|(i, log)| LocalizedLogEntry { + entry: log, + block_hash: hash.clone(), + block_number: number, + transaction_hash: hashes.get(index).cloned().unwrap_or_else(H256::new), + transaction_index: index, + log_index: log_index + i + }) + .collect::>() + }) + .collect::>() + + }) + .collect() + } +} + +impl MayPanic for Client { + fn on_panic(&self, closure: F) where F: OnPanicListener { + self.panic_handler.on_panic(closure); + } +} diff --git a/ethcore/src/client/config.rs b/ethcore/src/client/config.rs new file mode 100644 index 000000000..89e95ea06 --- /dev/null +++ b/ethcore/src/client/config.rs @@ -0,0 +1,32 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +pub use block_queue::BlockQueueConfig; +pub use blockchain::BlockChainConfig; +use util::journaldb; + +/// Client configuration. Includes configs for all sub-systems. +#[derive(Debug, Default)] +pub struct ClientConfig { + /// Block queue configuration. + pub queue: BlockQueueConfig, + /// Blockchain configuration. + pub blockchain: BlockChainConfig, + /// The JournalDB ("pruning") algorithm to use. + pub pruning: journaldb::Algorithm, + /// The name of the client instance. + pub name: String, +} diff --git a/ethcore/src/client/ids.rs b/ethcore/src/client/ids.rs new file mode 100644 index 000000000..79302354f --- /dev/null +++ b/ethcore/src/client/ids.rs @@ -0,0 +1,52 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Unique identifiers. + +use util::hash::H256; +use header::BlockNumber; + +/// Uniquely identifies block. +#[derive(Debug, PartialEq, Clone, Hash, Eq)] +pub enum BlockId { + /// Block's sha3. + /// Querying by hash is always faster. + Hash(H256), + /// Block number within canon blockchain. + Number(BlockNumber), + /// Earliest block (genesis). + Earliest, + /// Latest mined block. + Latest +} + +/// Uniquely identifies transaction. +#[derive(Debug, PartialEq, Clone, Hash, Eq)] +pub enum TransactionId { + /// Transaction's sha3. + Hash(H256), + /// Block id and transaction index within this block. + /// Querying by block position is always faster. + Location(BlockId, usize) +} + +/// Uniquely identifies Uncle. +pub struct UncleId ( + /// Block id. + pub BlockId, + /// Position in block. + pub usize +); diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs new file mode 100644 index 000000000..65733f3bf --- /dev/null +++ b/ethcore/src/client/mod.rs @@ -0,0 +1,132 @@ +// 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 database client. + +mod client; +mod config; +mod ids; +mod test_client; + +pub use self::client::*; +pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig}; +pub use self::ids::{BlockId, TransactionId, UncleId}; +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; +use blockchain::TreeRoute; +use block_queue::BlockQueueInfo; +use block::{ClosedBlock, SealedBlock}; +use header::{BlockNumber, Header}; +use transaction::{LocalizedTransaction, SignedTransaction}; +use log_entry::LocalizedLogEntry; +use filter::Filter; +use error::{ImportResult, Error}; +use receipt::LocalizedReceipt; + +/// Blockchain database client. Owns and manages a blockchain and a block queue. +pub trait BlockChainClient : Sync + Send { + /// Get raw block header data by block id. + fn block_header(&self, id: BlockId) -> Option; + + /// Get raw block body data by block id. + /// Block body is an RLP list of two items: uncles and transactions. + fn block_body(&self, id: BlockId) -> Option; + + /// Get raw block data by block header hash. + fn block(&self, id: BlockId) -> Option; + + /// Get block status by block header hash. + fn block_status(&self, id: BlockId) -> BlockStatus; + + /// Get block total difficulty. + fn block_total_difficulty(&self, id: BlockId) -> Option; + + /// Get address nonce. + fn nonce(&self, address: &Address) -> U256; + + /// Get block hash. + fn block_hash(&self, id: BlockId) -> Option; + + /// Get address code. + fn code(&self, address: &Address) -> Option; + + /// Get address balance. + fn balance(&self, address: &Address) -> U256; + + /// Get value of the storage at given position. + fn storage_at(&self, address: &Address, position: &H256) -> H256; + + /// Get transaction with given hash. + fn transaction(&self, id: TransactionId) -> Option; + + /// Get uncle with given id. + fn uncle(&self, id: UncleId) -> 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; + + /// Get latest state node + fn state_data(&self, hash: &H256) -> Option; + + /// Get raw block receipts data by block header hash. + fn block_receipts(&self, hash: &H256) -> Option; + + /// Import a block into the blockchain. + fn import_block(&self, bytes: Bytes) -> ImportResult; + + /// Get block queue information. + fn queue_info(&self) -> BlockQueueInfo; + + /// Clear block queue and abort all import activity. + fn clear_queue(&self); + + /// Get blockchain information. + fn chain_info(&self) -> BlockChainInfo; + + /// Get the best block header. + fn best_block_header(&self) -> Bytes { + // TODO: lock blockchain only once + self.block_header(BlockId::Hash(self.chain_info().best_block_hash)).unwrap() + } + + /// Returns numbers of blocks containing given bloom. + fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockId, to_block: BlockId) -> Option>; + + /// Returns logs matching given filter. + fn logs(&self, filter: Filter) -> Vec; + + // 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<(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 new file mode 100644 index 000000000..b2230af7b --- /dev/null +++ b/ethcore/src/client/test_client.rs @@ -0,0 +1,407 @@ +// 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 . + +//! Test client. + +use util::*; +use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action}; +use blockchain::TreeRoute; +use client::{BlockChainClient, BlockChainInfo, BlockStatus, BlockId, TransactionId, UncleId}; +use header::{Header as BlockHeader, BlockNumber}; +use filter::Filter; +use log_entry::LocalizedLogEntry; +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 { + /// Blocks. + pub blocks: RwLock>, + /// Mapping of numbers to hashes. + pub numbers: RwLock>, + /// Genesis block hash. + pub genesis_hash: H256, + /// Last block hash. + pub last_hash: RwLock, + /// Difficulty. + pub difficulty: RwLock, + /// Balances. + pub balances: RwLock>, + /// Storage. + pub storage: RwLock>, + /// Code. + pub code: RwLock>, + /// Execution result. + pub execution_result: RwLock>, + /// Transaction receipts. + pub receipts: RwLock>, +} + +#[derive(Clone)] +/// Used for generating test client blocks. +pub enum EachBlockWith { + /// Plain block. + Nothing, + /// Block with an uncle. + Uncle, + /// Block with a transaction. + Transaction, + /// Block with an uncle and transaction. + UncleAndTransaction +} + +impl Default for TestBlockChainClient { + fn default() -> Self { + TestBlockChainClient::new() + } +} + +impl TestBlockChainClient { + /// Creates new test client. + pub fn new() -> Self { + + let mut client = TestBlockChainClient { + blocks: RwLock::new(HashMap::new()), + numbers: RwLock::new(HashMap::new()), + genesis_hash: H256::new(), + last_hash: RwLock::new(H256::new()), + difficulty: RwLock::new(From::from(0)), + balances: RwLock::new(HashMap::new()), + storage: RwLock::new(HashMap::new()), + code: RwLock::new(HashMap::new()), + execution_result: RwLock::new(None), + receipts: RwLock::new(HashMap::new()), + }; + client.add_blocks(1, EachBlockWith::Nothing); // add genesis block + client.genesis_hash = client.last_hash.read().unwrap().clone(); + client + } + + /// Set the transaction receipt result + pub fn set_transaction_receipt(&self, id: TransactionId, receipt: LocalizedReceipt) { + self.receipts.write().unwrap().insert(id, receipt); + } + + /// 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); + } + + /// Set `code` at `address`. + pub fn set_code(&self, address: Address, code: Bytes) { + self.code.write().unwrap().insert(address, code); + } + + /// Set storage `position` to `value` for account `address`. + pub fn set_storage(&self, address: Address, position: H256, value: H256) { + self.storage.write().unwrap().insert((address, position), value); + } + + /// Add blocks to test client. + pub fn add_blocks(&self, count: usize, with: EachBlockWith) { + let len = self.numbers.read().unwrap().len(); + for n in len..(len + count) { + let mut header = BlockHeader::new(); + 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); + let mut uncle_header = BlockHeader::new(); + uncle_header.difficulty = From::from(n); + uncle_header.parent_hash = self.last_hash.read().unwrap().clone(); + uncle_header.number = n as BlockNumber; + uncles.append(&uncle_header); + header.uncles_hash = uncles.as_raw().sha3(); + uncles + }, + _ => RlpStream::new_list(0) + }; + let txs = match with { + EachBlockWith::Transaction | EachBlockWith::UncleAndTransaction => { + let mut txs = RlpStream::new_list(1); + let keypair = KeyPair::create().unwrap(); + let tx = Transaction { + action: Action::Create, + value: U256::from(100), + data: "3331600055".from_hex().unwrap(), + gas: U256::from(100_000), + gas_price: U256::one(), + nonce: U256::zero() + }; + let signed_tx = tx.sign(&keypair.secret()); + txs.append(&signed_tx); + txs.out() + }, + _ => rlp::NULL_RLP.to_vec() + }; + + let mut rlp = RlpStream::new_list(3); + rlp.append(&header); + rlp.append_raw(&txs, 1); + rlp.append_raw(uncles.as_raw(), 1); + self.import_block(rlp.as_raw().to_vec()).unwrap(); + } + } + + /// TODO: + pub fn corrupt_block(&mut self, n: BlockNumber) { + let hash = self.block_hash(BlockId::Number(n)).unwrap(); + let mut header: BlockHeader = decode(&self.block_header(BlockId::Number(n)).unwrap()); + header.parent_hash = H256::new(); + let mut rlp = RlpStream::new_list(3); + rlp.append(&header); + rlp.append_raw(&rlp::NULL_RLP, 1); + rlp.append_raw(&rlp::NULL_RLP, 1); + self.blocks.write().unwrap().insert(hash, rlp.out()); + } + + /// TODO: + pub fn block_hash_delta_minus(&mut self, delta: usize) -> H256 { + let blocks_read = self.numbers.read().unwrap(); + let index = blocks_read.len() - delta; + blocks_read[&index].clone() + } + + fn block_hash(&self, id: BlockId) -> Option { + match id { + BlockId::Hash(hash) => Some(hash), + BlockId::Number(n) => self.numbers.read().unwrap().get(&(n as usize)).cloned(), + BlockId::Earliest => self.numbers.read().unwrap().get(&0).cloned(), + BlockId::Latest => self.numbers.read().unwrap().get(&(self.numbers.read().unwrap().len() - 1)).cloned() + } + } +} + +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()) + } + + fn block_hash(&self, _id: BlockId) -> Option { + unimplemented!(); + } + + fn nonce(&self, _address: &Address) -> U256 { + U256::zero() + } + + fn code(&self, address: &Address) -> Option { + self.code.read().unwrap().get(address).cloned() + } + + fn balance(&self, address: &Address) -> U256 { + self.balances.read().unwrap().get(address).cloned().unwrap_or_else(U256::zero) + } + + fn storage_at(&self, address: &Address, position: &H256) -> H256 { + self.storage.read().unwrap().get(&(address.clone(), position.clone())).cloned().unwrap_or_else(H256::new) + } + + fn transaction(&self, _id: TransactionId) -> Option { + unimplemented!(); + } + + fn uncle(&self, _id: UncleId) -> Option { + unimplemented!(); + } + + fn transaction_receipt(&self, id: TransactionId) -> Option { + self.receipts.read().unwrap().get(&id).cloned() + } + + fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockId, _to_block: BlockId) -> Option> { + unimplemented!(); + } + + fn logs(&self, _filter: Filter) -> Vec { + 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 { + Err(block) + } + + fn block_header(&self, id: BlockId) -> Option { + self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec())) + } + + fn block_body(&self, id: BlockId) -> Option { + self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| { + let mut stream = RlpStream::new_list(2); + stream.append_raw(Rlp::new(&r).at(1).as_raw(), 1); + stream.append_raw(Rlp::new(&r).at(2).as_raw(), 1); + stream.out() + })) + } + + fn block(&self, id: BlockId) -> Option { + self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).cloned()) + } + + fn block_status(&self, id: BlockId) -> BlockStatus { + match id { + BlockId::Number(number) if (number as usize) < self.blocks.read().unwrap().len() => BlockStatus::InChain, + BlockId::Hash(ref hash) if self.blocks.read().unwrap().get(hash).is_some() => BlockStatus::InChain, + _ => BlockStatus::Unknown + } + } + + // works only if blocks are one after another 1 -> 2 -> 3 + fn tree_route(&self, from: &H256, to: &H256) -> Option { + Some(TreeRoute { + ancestor: H256::new(), + index: 0, + blocks: { + let numbers_read = self.numbers.read().unwrap(); + let mut adding = false; + + let mut blocks = Vec::new(); + for (_, hash) in numbers_read.iter().sort_by(|tuple1, tuple2| tuple1.0.cmp(tuple2.0)) { + if hash == to { + if adding { + blocks.push(hash.clone()); + } + adding = false; + break; + } + if hash == from { + adding = true; + } + if adding { + blocks.push(hash.clone()); + } + } + if adding { Vec::new() } else { blocks } + } + }) + } + + // TODO: returns just hashes instead of node state rlp(?) + fn state_data(&self, hash: &H256) -> Option { + // starts with 'f' ? + if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") { + let mut rlp = RlpStream::new(); + rlp.append(&hash.clone()); + return Some(rlp.out()); + } + None + } + + fn block_receipts(&self, hash: &H256) -> Option { + // starts with 'f' ? + if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") { + let receipt = BlockReceipts::new(vec![Receipt::new( + H256::zero(), + U256::zero(), + vec![])]); + let mut rlp = RlpStream::new(); + rlp.append(&receipt); + return Some(rlp.out()); + } + None + } + + fn import_block(&self, b: Bytes) -> ImportResult { + let header = Rlp::new(&b).val_at::(0); + let h = header.hash(); + let number: usize = header.number as usize; + if number > self.blocks.read().unwrap().len() { + panic!("Unexpected block number. Expected {}, got {}", self.blocks.read().unwrap().len(), number); + } + if number > 0 { + match self.blocks.read().unwrap().get(&header.parent_hash) { + Some(parent) => { + let parent = Rlp::new(parent).val_at::(0); + if parent.number != (header.number - 1) { + panic!("Unexpected block parent"); + } + }, + None => { + panic!("Unknown block parent {:?} for block {}", header.parent_hash, number); + } + } + } + let len = self.numbers.read().unwrap().len(); + if number == len { + { + let mut difficulty = self.difficulty.write().unwrap(); + *difficulty.deref_mut() = *difficulty.deref() + header.difficulty; + } + mem::replace(self.last_hash.write().unwrap().deref_mut(), h.clone()); + self.blocks.write().unwrap().insert(h.clone(), b); + self.numbers.write().unwrap().insert(number, h.clone()); + let mut parent_hash = header.parent_hash; + if number > 0 { + let mut n = number - 1; + while n > 0 && self.numbers.read().unwrap()[&n] != parent_hash { + *self.numbers.write().unwrap().get_mut(&n).unwrap() = parent_hash.clone(); + n -= 1; + parent_hash = Rlp::new(&self.blocks.read().unwrap()[&parent_hash]).val_at::(0).parent_hash; + } + } + } + else { + self.blocks.write().unwrap().insert(h.clone(), b.to_vec()); + } + Ok(h) + } + + fn queue_info(&self) -> BlockQueueInfo { + BlockQueueInfo { + verified_queue_size: 0, + unverified_queue_size: 0, + verifying_queue_size: 0, + max_queue_size: 0, + max_mem_use: 0, + mem_used: 0, + } + } + + fn clear_queue(&self) { + } + + fn chain_info(&self) -> BlockChainInfo { + BlockChainInfo { + total_difficulty: *self.difficulty.read().unwrap(), + pending_total_difficulty: *self.difficulty.read().unwrap(), + genesis_hash: self.genesis_hash.clone(), + best_block_hash: self.last_hash.read().unwrap().clone(), + best_block_number: self.blocks.read().unwrap().len() as BlockNumber - 1, + } + } +} diff --git a/ethcore/src/common.rs b/ethcore/src/common.rs index 5235e9f58..e91501217 100644 --- a/ethcore/src/common.rs +++ b/ethcore/src/common.rs @@ -25,4 +25,5 @@ pub use account::*; pub use transaction::*; pub use log_entry::*; pub use receipt::*; -pub use action_params::*; \ No newline at end of file +pub use action_params::*; +pub use trace::*; \ No newline at end of file diff --git a/ethcore/src/engine.rs b/ethcore/src/engine.rs index f86c943ee..7698af529 100644 --- a/ethcore/src/engine.rs +++ b/ethcore/src/engine.rs @@ -30,8 +30,6 @@ pub trait Engine : Sync + Send { /// The number of additional header fields required for this engine. fn seal_fields(&self) -> usize { 0 } - /// Default values of the additional fields RLP-encoded in a raw (non-list) harness. - fn seal_rlp(&self) -> Bytes { vec![] } /// Additional engine-specific information for the user/developer concerning `header`. fn extra_info(&self, _header: &Header) -> HashMap { HashMap::new() } @@ -49,6 +47,8 @@ pub trait Engine : Sync + Send { fn maximum_extra_data_size(&self) -> usize { decode(&self.spec().engine_params.get("maximumExtraDataSize").unwrap()) } /// Maximum number of uncles a block is allowed to declare. fn maximum_uncle_count(&self) -> usize { 2 } + /// The number of generations back that uncles can be. + fn maximum_uncle_age(&self) -> usize { 6 } /// The nonce with which accounts begin. fn account_start_nonce(&self) -> U256 { decode(&self.spec().engine_params.get("accountStartNonce").unwrap()) } @@ -76,9 +76,20 @@ pub trait Engine : Sync + Send { /// Verify a particular transaction is valid. fn verify_transaction(&self, _t: &SignedTransaction, _header: &Header) -> Result<(), Error> { Ok(()) } - /// Don't forget to call Super::populateFromParent when subclassing & overriding. + /// Verify the seal of a block. This is an auxilliary method that actually just calls other `verify_` methods + /// to get the job done. By default it must pass `verify_basic` and `verify_block_unordered`. If more or fewer + /// methods are needed for an Engine, this may be overridden. + fn verify_block_seal(&self, header: &Header) -> Result<(), Error> { + self.verify_block_basic(header, None).and_then(|_| self.verify_block_unordered(header, None)) + } + + /// Don't forget to call Super::populate_from_parent when subclassing & overriding. // TODO: consider including State in the params. - fn populate_from_parent(&self, _header: &mut Header, _parent: &Header) {} + fn populate_from_parent(&self, header: &mut Header, parent: &Header, _gas_floor_target: U256) { + header.difficulty = parent.difficulty; + header.gas_limit = parent.gas_limit; + header.note_dirty(); + } // TODO: builtin contract routing - to do this properly, it will require removing the built-in configuration-reading logic // from Spec into here and removing the Spec::builtins field. @@ -92,4 +103,14 @@ pub trait Engine : Sync + Send { fn execute_builtin(&self, a: &Address, input: &[u8], output: &mut [u8]) { self.spec().builtins.get(a).unwrap().execute(input, output); } // TODO: sealing stuff - though might want to leave this for later. + + /// Get a named parameter from the `spec()`'s `engine_params` item and convert to u64, or 0 if that fails. + fn u64_param(&self, name: &str) -> u64 { + self.spec().engine_params.get(name).map_or(0u64, |a| decode(&a)) + } + + /// Get a named parameter from the `spec()`'s `engine_params` item and convert to U256, or 0 if that fails. + fn u256_param(&self, name: &str) -> U256 { + self.spec().engine_params.get(name).map_or(x!(0), |a| decode(&a)) + } } diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index f75f338bf..02cd6678b 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -63,8 +63,33 @@ pub enum ExecutionError { } #[derive(Debug)] -/// Errors concerning transaction proessing. +/// 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, + }, + /// 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), } @@ -131,25 +156,14 @@ pub enum BlockError { #[derive(Debug)] /// Import to the block queue result pub enum ImportError { - /// Bad block detected - Bad(Option), - /// Already in the block chain + /// Already in the block chain. AlreadyInChain, - /// Already in the block queue + /// Already in the block queue. AlreadyQueued, - /// Unknown parent - UnknownParent, + /// Already marked as bad from a previous import (could mean parent is bad). + KnownBad, } -impl From for ImportError { - fn from(err: Error) -> ImportError { - ImportError::Bad(Some(err)) - } -} - -/// Result of import block operation. -pub type ImportResult = Result; - #[derive(Debug)] /// General error type which should be capable of representing all errors in ethcore. pub enum Error { @@ -163,14 +177,29 @@ pub enum Error { Execution(ExecutionError), /// Error concerning transaction processing. Transaction(TransactionError), + /// Error concerning block import. + Import(ImportError), + /// PoW hash is invalid or out of date. + PowHashInvalid, + /// The value of the nonce or mishash is invalid. + PowInvalid, } +/// Result of import block operation. +pub type ImportResult = Result; + impl From for Error { fn from(err: TransactionError) -> Error { Error::Transaction(err) } } +impl From for Error { + fn from(err: ImportError) -> Error { + Error::Import(err) + } +} + impl From for Error { fn from(err: BlockError) -> Error { Error::Block(err) diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index c45b22102..d2c56ebf1 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -57,16 +57,6 @@ impl Ethash { u256_params: RwLock::new(HashMap::new()) } } - - fn u64_param(&self, name: &str) -> u64 { - *self.u64_params.write().unwrap().entry(name.to_owned()).or_insert_with(|| - self.spec().engine_params.get(name).map_or(0u64, |a| decode(&a))) - } - - fn u256_param(&self, name: &str) -> U256 { - *self.u256_params.write().unwrap().entry(name.to_owned()).or_insert_with(|| - self.spec().engine_params.get(name).map_or(x!(0), |a| decode(&a))) - } } impl Engine for Ethash { @@ -74,8 +64,6 @@ impl Engine for Ethash { fn version(&self) -> SemanticVersion { SemanticVersion::new(1, 0, 0) } // Two fields - mix fn seal_fields(&self) -> usize { 2 } - // Two empty data items in RLP. - fn seal_rlp(&self) -> Bytes { encode(&H64::new()).to_vec() } /// Additional engine-specific information for the user/developer concerning `header`. fn extra_info(&self, _header: &Header) -> HashMap { HashMap::new() } @@ -87,20 +75,16 @@ impl Engine for Ethash { fn schedule(&self, env_info: &EnvInfo) -> Schedule { trace!(target: "client", "Creating schedule. param={:?}, fCML={}", self.spec().engine_params.get("frontierCompatibilityModeLimit"), self.u64_param("frontierCompatibilityModeLimit")); - match env_info.number < self.u64_param("frontierCompatibilityModeLimit") { - true => { - Schedule::new_frontier() - }, - _ => { - Schedule::new_homestead() - }, + if env_info.number < self.u64_param("frontierCompatibilityModeLimit") { + Schedule::new_frontier() + } else { + Schedule::new_homestead() } } - fn populate_from_parent(&self, header: &mut Header, parent: &Header) { + fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256) { header.difficulty = self.calculate_difficuty(header, parent); header.gas_limit = { - let gas_floor_target: U256 = x!(3141562); let gas_limit = parent.gas_limit; let bound_divisor = self.u256_param("gasLimitBoundDivisor"); if gas_limit < gas_floor_target { @@ -109,7 +93,7 @@ impl Engine for Ethash { max(gas_floor_target, gas_limit - gas_limit / bound_divisor + x!(1) + (header.gas_used * x!(6) / x!(5)) / bound_divisor) } }; - + header.note_dirty(); // info!("ethash: populate_from_parent #{}: difficulty={} and gas_limit={}", header.number, header.difficulty, header.gas_limit); } @@ -147,9 +131,10 @@ impl Engine for Ethash { } let difficulty = Ethash::boundary_to_difficulty(&Ethash::from_ethash(quick_get_difficulty( - &Ethash::to_ethash(header.bare_hash()), - header.nonce().low_u64(), - &Ethash::to_ethash(header.mix_hash())))); + &Ethash::to_ethash(header.bare_hash()), + header.nonce().low_u64(), + &Ethash::to_ethash(header.mix_hash()) + ))); if difficulty < header.difficulty { return Err(From::from(BlockError::InvalidProofOfWork(OutOfBounds { min: Some(header.difficulty), max: None, found: difficulty }))); } @@ -189,7 +174,7 @@ impl Engine for Ethash { let min_gas = parent.gas_limit - parent.gas_limit / gas_limit_divisor; let max_gas = parent.gas_limit + parent.gas_limit / gas_limit_divisor; if header.gas_limit <= min_gas || header.gas_limit >= max_gas { - return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit }))); + return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit }))); } Ok(()) } @@ -204,9 +189,19 @@ impl Engine for Ethash { fn verify_transaction(&self, t: &SignedTransaction, _header: &Header) -> Result<(), Error> { t.sender().map(|_|()) // Perform EC recovery and cache sender } + + fn u64_param(&self, name: &str) -> u64 { + *self.u64_params.write().unwrap().entry(name.to_owned()).or_insert_with(|| + self.spec().engine_params.get(name).map_or(0u64, |a| decode(&a))) + } + + fn u256_param(&self, name: &str) -> U256 { + *self.u256_params.write().unwrap().entry(name.to_owned()).or_insert_with(|| + self.spec().engine_params.get(name).map_or(x!(0), |a| decode(&a))) + } } -#[allow(wrong_self_convention)] // to_ethash should take self +#[cfg_attr(feature="dev", allow(wrong_self_convention))] // to_ethash should take self impl Ethash { fn calculate_difficuty(&self, header: &Header, parent: &Header) -> U256 { const EXP_DIFF_PERIOD: u64 = 100000; @@ -220,8 +215,8 @@ impl Ethash { let frontier_limit = self.u64_param("frontierCompatibilityModeLimit"); let mut target = if header.number < frontier_limit { if header.timestamp >= parent.timestamp + duration_limit { - parent.difficulty - (parent.difficulty / difficulty_bound_divisor) - } + parent.difficulty - (parent.difficulty / difficulty_bound_divisor) + } else { parent.difficulty + (parent.difficulty / difficulty_bound_divisor) } @@ -243,11 +238,22 @@ impl Ethash { } target } - - fn boundary_to_difficulty(boundary: &H256) -> U256 { + + /// Convert an Ethash boundary to its original difficulty. Basically just `f(x) = 2^256 / x`. + pub fn boundary_to_difficulty(boundary: &H256) -> U256 { U256::from((U512::one() << 256) / x!(U256::from(boundary.as_slice()))) } + /// Convert an Ethash difficulty to the target boundary. Basically just `f(x) = 2^256 / x`. + pub fn difficulty_to_boundary(difficulty: &U256) -> H256 { + x!(U256::from((U512::one() << 256) / x!(difficulty))) + } + + /// Given the `block_number`, determine the seed hash for Ethash. + pub fn get_seedhash(number: BlockNumber) -> H256 { + Self::from_ethash(ethash::get_seedhash(number)) + } + fn to_ethash(hash: H256) -> EH256 { unsafe { mem::transmute(hash) } } @@ -258,12 +264,20 @@ impl Ethash { } impl Header { - fn nonce(&self) -> H64 { + /// Get the none field of the header. + pub fn nonce(&self) -> H64 { decode(&self.seal()[1]) } - fn mix_hash(&self) -> H256 { + + /// Get the mix hash field of the header. + pub fn mix_hash(&self) -> H256 { decode(&self.seal()[0]) } + + /// Set the nonce and mix hash fields of the header. + pub fn set_nonce_and_mix_hash(&mut self, nonce: &H64, mix_hash: &H256) { + self.seal = vec![encode(mix_hash).to_vec(), encode(nonce).to_vec()]; + } } #[cfg(test)] @@ -283,9 +297,9 @@ mod tests { let genesis_header = engine.spec().genesis_header(); let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); - engine.spec().ensure_db_good(&mut db); + engine.spec().ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; - let b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]); + let b = OpenBlock::new(engine.deref(), false, db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]); let b = b.close(); assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap()); } @@ -296,9 +310,9 @@ mod tests { let genesis_header = engine.spec().genesis_header(); let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); - engine.spec().ensure_db_good(&mut db); + engine.spec().ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; - let mut b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]); + let mut b = OpenBlock::new(engine.deref(), false, db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]); let mut uncle = Header::new(); let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106"); uncle.author = uncle_author.clone(); diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index 0d1dcd8d5..8c2ae6b37 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -61,7 +61,7 @@ mod tests { let genesis_header = engine.spec().genesis_header(); let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); - engine.spec().ensure_db_good(&mut db); + engine.spec().ensure_db_good(db.as_hashdb_mut()); let s = State::from_existing(db, genesis_header.state_root.clone(), engine.account_start_nonce()); assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000001")), U256::from(1u64)); assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000002")), U256::from(1u64)); diff --git a/ethcore/src/evm/evm.rs b/ethcore/src/evm/evm.rs index 28eb96f44..c1107f003 100644 --- a/ethcore/src/evm/evm.rs +++ b/ethcore/src/evm/evm.rs @@ -65,7 +65,7 @@ pub enum Error { /// Evm result. /// -/// Returns gas_left if execution is successfull, otherwise error. +/// Returns gas_left if execution is successful, otherwise error. pub type Result = result::Result; /// Evm interface. diff --git a/ethcore/src/evm/ext.rs b/ethcore/src/evm/ext.rs index ae4cff3be..4986b12c8 100644 --- a/ethcore/src/evm/ext.rs +++ b/ethcore/src/evm/ext.rs @@ -16,9 +16,7 @@ //! Interface for Evm externalities. -use common::Bytes; -use util::hash::*; -use util::uint::*; +use util::common::*; use evm::{Schedule, Error}; use env_info::*; @@ -60,22 +58,23 @@ pub trait Ext { fn blockhash(&self, number: &U256) -> H256; /// Creates new contract. - /// + /// /// Returns gas_left and contract address if contract creation was succesfull. fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult; /// Message call. - /// + /// /// Returns Err, if we run out of gas. - /// Otherwise returns call_result which contains gas left + /// Otherwise returns call_result which contains gas left /// and true if subcall was successfull. - fn call(&mut self, - gas: &U256, - sender_address: &Address, - receive_address: &Address, + #[cfg_attr(feature="dev", allow(too_many_arguments))] + fn call(&mut self, + gas: &U256, + sender_address: &Address, + receive_address: &Address, value: Option, - data: &[u8], - code_address: &Address, + data: &[u8], + code_address: &Address, output: &mut [u8]) -> MessageCallResult; /// Returns code at given address @@ -99,7 +98,7 @@ pub trait Ext { fn env_info(&self) -> &EnvInfo; /// Returns current depth of execution. - /// + /// /// If contract A calls contract B, and contract B calls C, /// then A depth is 0, B is 1, C is 2 and so on. fn depth(&self) -> usize; diff --git a/ethcore/src/evm/factory.rs b/ethcore/src/evm/factory.rs index 4a9bd38ba..65add0050 100644 --- a/ethcore/src/evm/factory.rs +++ b/ethcore/src/evm/factory.rs @@ -25,7 +25,7 @@ use evm::Evm; /// Type of EVM to use. pub enum VMType { /// JIT EVM - #[cfg(feature="jit")] + #[cfg(feature = "jit")] Jit, /// RUST EVM Interpreter @@ -52,13 +52,13 @@ impl fmt::Display for VMType { #[cfg(feature = "json-tests")] impl VMType { /// Return all possible VMs (JIT, Interpreter) - #[cfg(feature="jit")] + #[cfg(feature = "jit")] pub fn all() -> Vec { vec![VMType::Jit, VMType::Interpreter] } /// Return all possible VMs (Interpreter) - #[cfg(not(feature="jit"))] + #[cfg(not(feature = "jit"))] pub fn all() -> Vec { vec![VMType::Interpreter] } @@ -66,12 +66,12 @@ impl VMType { /// Evm factory. Creates appropriate Evm. pub struct Factory { - evm : VMType + evm: VMType } impl Factory { /// Create fresh instance of VM - #[cfg(feature="jit")] + #[cfg(feature = "jit")] pub fn create(&self) -> Box { match self.evm { VMType::Jit => { @@ -84,7 +84,7 @@ impl Factory { } /// Create fresh instance of VM - #[cfg(not(feature="jit"))] + #[cfg(not(feature = "jit"))] pub fn create(&self) -> Box { match self.evm { VMType::Interpreter => { diff --git a/ethcore/src/evm/interpreter.rs b/ethcore/src/evm/interpreter.rs index 50c0377ac..eb29ef257 100644 --- a/ethcore/src/evm/interpreter.rs +++ b/ethcore/src/evm/interpreter.rs @@ -243,7 +243,7 @@ struct CodeReader<'a> { code: &'a Bytes } -#[allow(len_without_is_empty)] +#[cfg_attr(feature="dev", allow(len_without_is_empty))] impl<'a> CodeReader<'a> { /// Get `no_of_bytes` from code and convert to U256. Move PC fn read(&mut self, no_of_bytes: usize) -> U256 { @@ -258,7 +258,7 @@ impl<'a> CodeReader<'a> { } } -#[allow(enum_variant_names)] +#[cfg_attr(feature="dev", allow(enum_variant_names))] enum InstructionCost { Gas(U256), GasMem(U256, U256), @@ -299,7 +299,7 @@ impl evm::Evm for Interpreter { let (gas_cost, mem_size) = try!(self.get_gas_cost_mem(ext, instruction, &mut mem, &stack)); try!(self.verify_gas(¤t_gas, &gas_cost)); mem.expand(mem_size); - current_gas -= gas_cost; + current_gas = current_gas - gas_cost; //TODO: use operator -= evm_debug!({ println!("[0x{:x}][{}(0x{:x}) Gas: {:x}\n Gas Before: {:x}", @@ -320,7 +320,7 @@ impl evm::Evm for Interpreter { match result { InstructionResult::Ok => {}, InstructionResult::UnusedGas(gas) => { - current_gas += gas; + current_gas = current_gas + gas; //TODO: use operator += }, InstructionResult::UseAllGas => { current_gas = U256::zero(); @@ -347,13 +347,14 @@ impl evm::Evm for Interpreter { } impl Interpreter { - #[allow(cyclomatic_complexity)] - fn get_gas_cost_mem(&self, - ext: &evm::Ext, - instruction: Instruction, - mem: &mut Memory, - stack: &Stack - ) -> Result<(U256, usize), evm::Error> { + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] + fn get_gas_cost_mem( + &self, + ext: &evm::Ext, + instruction: Instruction, + mem: &mut Memory, + stack: &Stack + ) -> Result<(U256, usize), evm::Error> { let schedule = ext.schedule(); let info = instructions::get_info(instruction); @@ -521,15 +522,17 @@ impl Interpreter { Ok(overflowing!(offset.overflowing_add(size.clone()))) } - fn exec_instruction(&self, - gas: Gas, - params: &ActionParams, - ext: &mut evm::Ext, - instruction: Instruction, - code: &mut CodeReader, - mem: &mut Memory, - stack: &mut Stack - ) -> Result { + #[cfg_attr(feature="dev", allow(too_many_arguments))] + fn exec_instruction( + &self, + gas: Gas, + params: &ActionParams, + ext: &mut evm::Ext, + instruction: Instruction, + code: &mut CodeReader, + mem: &mut Memory, + stack: &mut Stack + ) -> Result { match instruction { instructions::JUMP => { let jump = stack.pop_back(); @@ -581,9 +584,10 @@ impl Interpreter { let code_address = stack.pop_back(); let code_address = u256_to_address(&code_address); - let value = match instruction == instructions::DELEGATECALL { - true => None, - false => Some(stack.pop_back()) + let value = if instruction == instructions::DELEGATECALL { + None + } else { + Some(stack.pop_back()) }; let in_off = stack.pop_back(); diff --git a/ethcore/src/evm/tests.rs b/ethcore/src/evm/tests.rs index 02f929192..445c0be41 100644 --- a/ethcore/src/evm/tests.rs +++ b/ethcore/src/evm/tests.rs @@ -25,9 +25,8 @@ struct FakeLogEntry { } #[derive(PartialEq, Eq, Hash, Debug)] -#[allow(enum_variant_names)] // Common prefix is C ;) enum FakeCallType { - CALL, CREATE + Call, Create } #[derive(PartialEq, Eq, Hash, Debug)] @@ -56,7 +55,7 @@ struct FakeExt { info: EnvInfo, schedule: Schedule, balances: HashMap, - calls: HashSet + calls: HashSet, } impl FakeExt { @@ -94,7 +93,7 @@ impl Ext for FakeExt { fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult { self.calls.insert(FakeCall { - call_type: FakeCallType::CREATE, + call_type: FakeCallType::Create, gas: *gas, sender_address: None, receive_address: None, @@ -115,7 +114,7 @@ impl Ext for FakeExt { _output: &mut [u8]) -> MessageCallResult { self.calls.insert(FakeCall { - call_type: FakeCallType::CALL, + call_type: FakeCallType::Call, gas: *gas, sender_address: Some(sender_address.clone()), receive_address: Some(receive_address.clone()), @@ -347,7 +346,7 @@ fn test_log_empty(factory: super::Factory) { assert_eq!(gas_left, U256::from(99_619)); assert_eq!(ext.logs.len(), 1); assert_eq!(ext.logs[0].topics.len(), 0); - assert_eq!(ext.logs[0].data, vec![]); + assert!(ext.logs[0].data.is_empty()); } evm_test!{test_log_sender: test_log_sender_jit, test_log_sender_int} @@ -909,7 +908,7 @@ fn test_calls(factory: super::Factory) { }; assert_set_contains(&ext.calls, &FakeCall { - call_type: FakeCallType::CALL, + call_type: FakeCallType::Call, gas: U256::from(2556), sender_address: Some(address.clone()), receive_address: Some(code_address.clone()), @@ -918,7 +917,7 @@ fn test_calls(factory: super::Factory) { code_address: Some(code_address.clone()) }); assert_set_contains(&ext.calls, &FakeCall { - call_type: FakeCallType::CALL, + call_type: FakeCallType::Call, gas: U256::from(2556), sender_address: Some(address.clone()), receive_address: Some(address.clone()), diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 782063cb2..0081cdf1e 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -37,30 +37,39 @@ 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, + /// Gas used during execution of transaction. pub gas_used: U256, + /// Gas refunded after the execution of transaction. /// To get gas that was required up front, add `refunded` and `gas_used`. pub refunded: U256, + /// Cumulative gas used in current block so far. /// /// `cumulative_gas_used = gas_used(t0) + gas_used(t1) + ... gas_used(tn)` /// /// where `tn` is current transaction. pub cumulative_gas_used: U256, + /// Vector of logs generated by transaction. pub logs: Vec, + /// Addresses of contracts created during execution of transaction. /// Ordered from earliest creation. /// /// 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, + /// The trace of this transaction. + pub trace: Option, } /// Transaction execution result. @@ -71,38 +80,37 @@ pub struct Executive<'a> { state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, - depth: usize + depth: usize, } impl<'a> Executive<'a> { /// Basic constructor. pub fn new(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine) -> Self { - Executive::new_with_depth(state, info, engine, 0) - } - - /// Populates executive from parent properties. Increments executive depth. - pub fn from_parent(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, depth: usize) -> Self { - Executive::new_with_depth(state, info, engine, depth + 1) - } - - /// Helper constructor. Should be used to create `Executive` with desired depth. - /// Private. - fn new_with_depth(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, depth: usize) -> Self { Executive { state: state, info: info, engine: engine, - depth: depth + depth: 0, + } + } + + /// Populates executive from parent properties. Increments executive depth. + pub fn from_parent(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, parent_depth: usize) -> Self { + Executive { + state: state, + info: info, + engine: engine, + depth: parent_depth + 1, } } /// Creates `Externalities` from `Executive`. - pub fn as_externalities<'_>(&'_ mut self, origin_info: OriginInfo, substate: &'_ mut Substate, output: OutputPolicy<'_>) -> Externalities { + pub fn as_externalities<'_>(&'_ mut self, origin_info: OriginInfo, substate: &'_ mut Substate, output: OutputPolicy<'_, '_>) -> Externalities { Externalities::new(self.state, self.info, self.engine, self.depth, origin_info, substate, output) } /// This funtion should be used to execute transaction. - pub fn transact(&'a mut self, t: &SignedTransaction) -> Result { + pub fn transact(&'a mut self, t: &SignedTransaction, tracing: bool) -> Result { let sender = try!(t.sender()); let nonce = self.state.nonce(&sender); @@ -143,9 +151,9 @@ impl<'a> Executive<'a> { self.state.inc_nonce(&sender); self.state.sub_balance(&sender, &U256::from(gas_cost)); - let mut substate = Substate::new(); + let mut substate = Substate::new(tracing); - 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 +167,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 +183,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 { @@ -188,6 +196,7 @@ impl<'a> Executive<'a> { if (self.depth + 1) % MAX_VM_DEPTH_FOR_THREAD != 0 { let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy); let vm_factory = self.engine.vm_factory(); + trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call); return vm_factory.create().exec(params, &mut ext); } @@ -237,25 +246,49 @@ impl<'a> Executive<'a> { Err(evm::Error::OutOfGas) } } - } else if params.code.is_some() { - // if destination is a contract, do normal message call - - // part of substate that may be reverted - let mut unconfirmed_substate = Substate::new(); - - let res = { - self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output)) - }; - - trace!("exec: sstore-clears={}\n", unconfirmed_substate.sstore_clears_count); - trace!("exec: substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate); - self.enact_result(&res, substate, unconfirmed_substate); - trace!("exec: new substate={:?}\n", substate); - res } else { - // otherwise, nothing - self.state.clear_snapshot(); - Ok(params.gas) + // if destination is a contract, do normal message call + + // don't trace if it's DELEGATECALL or CALLCODE. + let should_trace = if let ActionValue::Transfer(_) = params.value { + params.code_address == params.address && substate.subtraces.is_some() + } else { false }; + + // transaction tracing stuff. None if there's no tracing. + let (mut trace_info, mut trace_output) = if should_trace { + (Some((TraceAction::from_call(¶ms), self.depth)), Some(vec![])) + } else { (None, None) }; + + if params.code.is_some() { + // part of substate that may be reverted + let mut unconfirmed_substate = Substate::new(should_trace); + + let res = { + self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut())) + }; + + trace!(target: "executive", "res={:?}", res); + + // if there's tracing, make up trace_info's result with trace_output and some arithmetic. + if let Some((TraceAction::Call(ref mut c), _)) = trace_info { + c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, trace_output.expect("trace_info is Some: so should_trace: qed"))); + } + + trace!(target: "executive", "substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate); + + self.enact_result(&res, substate, unconfirmed_substate, trace_info); + trace!(target: "executive", "enacted: substate={:?}\n", substate); + res + } else { + // otherwise it's just a basic transaction, only do tracing, if necessary. + trace!(target: "executive", "Basic message (send funds) should_trace={}", should_trace); + self.state.clear_snapshot(); + if let Some((TraceAction::Call(ref mut c), _)) = trace_info { + c.result = Some((x!(0), vec![])); + } + substate.accrue_trace(if should_trace {Some(vec![])} else {None}, trace_info); + Ok(params.gas) + } } } @@ -267,7 +300,7 @@ impl<'a> Executive<'a> { self.state.snapshot(); // part of substate that may be reverted - let mut unconfirmed_substate = Substate::new(); + let mut unconfirmed_substate = Substate::new(substate.subtraces.is_some()); // create contract and transfer value to it if necessary let prev_bal = self.state.balance(¶ms.address); @@ -278,15 +311,26 @@ impl<'a> Executive<'a> { self.state.new_contract(¶ms.address, prev_bal); } + let mut trace_info = substate.subtraces.as_ref().map(|_| (TraceAction::from_create(¶ms), self.depth)); + let mut trace_output = trace_info.as_ref().map(|_| vec![]); + let created = params.address.clone(); + let res = { - self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract) + self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(trace_output.as_mut())) }; - self.enact_result(&res, substate, unconfirmed_substate); + + if let Some((TraceAction::Create(ref mut c), _)) = trace_info { + c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, created, trace_output.expect("trace_info is Some: qed"))); + } + + trace!(target: "executive", "trace_info={:?}", trace_info); + + self.enact_result(&res, substate, unconfirmed_substate, trace_info); res } /// 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 @@ -317,6 +361,8 @@ impl<'a> Executive<'a> { self.state.kill_account(address); } + let trace = substate.subtraces.and_then(|mut v| v.pop()); + match result { Err(evm::Error::Internal) => Err(ExecutionError::Internal), Err(_) => { @@ -326,7 +372,9 @@ 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, + trace: trace, }) }, _ => { @@ -337,12 +385,14 @@ impl<'a> Executive<'a> { cumulative_gas_used: self.info.gas_used + gas_used, logs: substate.logs, contracts_created: substate.contracts_created, + output: output, + trace: trace, }) }, } } - fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate) { + fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate, maybe_info: Option<(TraceAction, usize)>) { match *result { Err(evm::Error::OutOfGas) | Err(evm::Error::BadJumpDestination {..}) @@ -350,10 +400,11 @@ impl<'a> Executive<'a> { | Err(evm::Error::StackUnderflow {..}) | Err(evm::Error::OutOfStack {..}) => { self.state.revert_snapshot(); + substate.accrue_trace(un_substate.subtraces, maybe_info) }, Ok(_) | Err(evm::Error::Internal) => { self.state.clear_snapshot(); - substate.accrue(un_substate) + substate.accrue(un_substate, maybe_info) } } } @@ -391,7 +442,7 @@ mod tests { state.add_balance(&sender, &U256::from(0x100u64)); let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); - let mut substate = Substate::new(); + let mut substate = Substate::new(false); let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); @@ -408,8 +459,8 @@ mod tests { // TODO: just test state root. } - evm_test!{test_create_contract: test_create_contract_jit, test_create_contract_int} - fn test_create_contract(factory: Factory) { + evm_test!{test_create_contract_out_of_depth: test_create_contract_out_of_depth_jit, test_create_contract_out_of_depth_int} + fn test_create_contract_out_of_depth(factory: Factory) { // code: // // 7c 601080600c6000396000f3006000355415600957005b60203560003555 - push 29 bytes? @@ -450,7 +501,7 @@ mod tests { state.add_balance(&sender, &U256::from(100)); let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); - let mut substate = Substate::new(); + let mut substate = Substate::new(false); let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); @@ -462,6 +513,137 @@ mod tests { assert_eq!(substate.contracts_created.len(), 0); } + evm_test!{test_call_to_create: test_call_to_create_jit, test_call_to_create_int} + fn test_call_to_create(factory: Factory) { + // code: + // + // 7c 601080600c6000396000f3006000355415600957005b60203560003555 - push 29 bytes? + // 60 00 - push 0 + // 52 + // 60 1d - push 29 + // 60 03 - push 3 + // 60 17 - push 17 + // f0 - create + // 60 00 - push 0 + // 55 sstore + // + // other code: + // + // 60 10 - push 16 + // 80 - duplicate first stack item + // 60 0c - push 12 + // 60 00 - push 0 + // 39 - copy current code to memory + // 60 00 - push 0 + // f3 - return + + let code = "7c601080600c6000396000f3006000355415600957005b60203560003555600052601d60036017f0600055".from_hex().unwrap(); + + let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); + let address = contract_address(&sender, &U256::zero()); + // TODO: add tests for 'callcreate' + //let next_address = contract_address(&address, &U256::zero()); + let mut params = ActionParams::default(); + params.address = address.clone(); + params.code_address = address.clone(); + params.sender = sender.clone(); + params.origin = sender.clone(); + params.gas = U256::from(100_000); + params.code = Some(code.clone()); + params.value = ActionValue::Transfer(U256::from(100)); + let mut state_result = get_temp_state(); + let mut state = state_result.reference_mut(); + state.add_balance(&sender, &U256::from(100)); + let info = EnvInfo::default(); + let engine = TestEngine::new(5, factory); + let mut substate = Substate::new(true); + + let gas_left = { + let mut ex = Executive::new(&mut state, &info, &engine); + let output = BytesRef::Fixed(&mut[0u8;0]); + ex.call(params, &mut substate, output).unwrap() + }; + + println!("trace: {:?}", substate.subtraces); + let expected_trace = Some(vec![ Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("cd1722f3947def4cf144679da39c4c32bdc35681"), + to: x!("b010143a42d5980c7e5ef0e4a4416dc098a4fed3"), + value: x!(100), + gas: x!(100000), + input: vec![], + result: Some((x!(55248), vec![])) + }), + subs: vec![Trace { + depth: 1, + action: TraceAction::Create(TraceCreate { + from: x!("b010143a42d5980c7e5ef0e4a4416dc098a4fed3"), + value: x!(23), + gas: x!(67979), + init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], + result: Some((x!(3224), x!("c6d80f262ae5e0f164e5fde365044d7ada2bfa34"), vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53])), + }), + subs: vec![] + }] + } ]); + assert_eq!(substate.subtraces, expected_trace); + assert_eq!(gas_left, U256::from(44_752)); + } + + evm_test!{test_create_contract: test_create_contract_jit, test_create_contract_int} + fn test_create_contract(factory: Factory) { + // code: + // + // 60 10 - push 16 + // 80 - duplicate first stack item + // 60 0c - push 12 + // 60 00 - push 0 + // 39 - copy current code to memory + // 60 00 - push 0 + // f3 - return + + let code = "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(); + + let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); + let address = contract_address(&sender, &U256::zero()); + // TODO: add tests for 'callcreate' + //let next_address = contract_address(&address, &U256::zero()); + let mut params = ActionParams::default(); + params.address = address.clone(); + params.sender = sender.clone(); + params.origin = sender.clone(); + params.gas = U256::from(100_000); + params.code = Some(code.clone()); + params.value = ActionValue::Transfer(x!(100)); + let mut state_result = get_temp_state(); + let mut state = state_result.reference_mut(); + state.add_balance(&sender, &U256::from(100)); + let info = EnvInfo::default(); + let engine = TestEngine::new(5, factory); + let mut substate = Substate::new(true); + + let gas_left = { + let mut ex = Executive::new(&mut state, &info, &engine); + ex.create(params.clone(), &mut substate).unwrap() + }; + + println!("trace: {:?}", substate.subtraces); + let expected_trace = Some(vec![Trace { + depth: 0, + action: TraceAction::Create(TraceCreate { + from: params.sender, + value: x!(100), + gas: params.gas, + init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], + result: Some((x!(3224), params.address, vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53])), + }), + subs: vec![] + } ]); + assert_eq!(substate.subtraces, expected_trace); + assert_eq!(gas_left, U256::from(96_776)); + } + evm_test!{test_create_contract_value_too_high: test_create_contract_value_too_high_jit, test_create_contract_value_too_high_int} fn test_create_contract_value_too_high(factory: Factory) { // code: @@ -504,7 +686,7 @@ mod tests { state.add_balance(&sender, &U256::from(100)); let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); - let mut substate = Substate::new(); + let mut substate = Substate::new(false); let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); @@ -556,7 +738,7 @@ mod tests { state.add_balance(&sender, &U256::from(100)); let info = EnvInfo::default(); let engine = TestEngine::new(1024, factory); - let mut substate = Substate::new(); + let mut substate = Substate::new(false); { let mut ex = Executive::new(&mut state, &info, &engine); @@ -617,7 +799,7 @@ mod tests { let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); - let mut substate = Substate::new(); + let mut substate = Substate::new(false); let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); @@ -662,7 +844,7 @@ mod tests { state.init_code(&address, code.clone()); let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); - let mut substate = Substate::new(); + let mut substate = Substate::new(false); let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); @@ -699,7 +881,7 @@ mod tests { let executed = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.transact(&t).unwrap() + ex.transact(&t, false).unwrap() }; assert_eq!(executed.gas, U256::from(100_000)); @@ -732,7 +914,7 @@ mod tests { let res = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.transact(&t) + ex.transact(&t, false) }; match res { @@ -763,7 +945,7 @@ mod tests { let res = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.transact(&t) + ex.transact(&t, false) }; match res { @@ -796,7 +978,7 @@ mod tests { let res = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.transact(&t) + ex.transact(&t, false) }; match res { @@ -829,7 +1011,7 @@ mod tests { let res = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.transact(&t) + ex.transact(&t, false) }; match res { @@ -859,7 +1041,7 @@ mod tests { state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap()); let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); - let mut substate = Substate::new(); + let mut substate = Substate::new(false); let result = { let mut ex = Executive::new(&mut state, &info, &engine); diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 360bd9738..3f9d4ff08 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -23,12 +23,12 @@ use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult}; use substate::*; /// Policy for handling output data on `RETURN` opcode. -pub enum OutputPolicy<'a> { +pub enum OutputPolicy<'a, 'b> { /// Return reference to fixed sized output. /// Used for message calls. - Return(BytesRef<'a>), + Return(BytesRef<'a>, Option<&'b mut Bytes>), /// Init new contract as soon as `RETURN` is called. - InitContract + InitContract(Option<&'b mut Bytes>), } /// Transaction properties that externalities need to know about. @@ -62,18 +62,19 @@ pub struct Externalities<'a> { origin_info: OriginInfo, substate: &'a mut Substate, schedule: Schedule, - output: OutputPolicy<'a> + output: OutputPolicy<'a, 'a> } impl<'a> Externalities<'a> { /// Basic `Externalities` constructor. pub fn new(state: &'a mut State, - env_info: &'a EnvInfo, - engine: &'a Engine, - depth: usize, - origin_info: OriginInfo, - substate: &'a mut Substate, - output: OutputPolicy<'a>) -> Self { + env_info: &'a EnvInfo, + engine: &'a Engine, + depth: usize, + origin_info: OriginInfo, + substate: &'a mut Substate, + output: OutputPolicy<'a, 'a> + ) -> Self { Externalities { state: state, env_info: env_info, @@ -152,13 +153,15 @@ impl<'a> Ext for Externalities<'a> { } fn call(&mut self, - gas: &U256, - sender_address: &Address, - receive_address: &Address, - value: Option, - data: &[u8], - code_address: &Address, - output: &mut [u8]) -> MessageCallResult { + gas: &U256, + sender_address: &Address, + receive_address: &Address, + value: Option, + data: &[u8], + code_address: &Address, + output: &mut [u8] + ) -> MessageCallResult { + trace!(target: "externalities", "call"); let mut params = ActionParams { sender: sender_address.clone(), @@ -188,22 +191,33 @@ impl<'a> Ext for Externalities<'a> { self.state.code(address).unwrap_or_else(|| vec![]) } - #[allow(match_ref_pats)] + #[cfg_attr(feature="dev", allow(match_ref_pats))] fn ret(&mut self, gas: &U256, data: &[u8]) -> Result { - match &mut self.output { - &mut OutputPolicy::Return(BytesRef::Fixed(ref mut slice)) => unsafe { + let handle_copy = |to: &mut Option<&mut Bytes>| { + to.as_mut().map(|b| **b = data.to_owned()); + }; + match self.output { + OutputPolicy::Return(BytesRef::Fixed(ref mut slice), ref mut copy) => { + handle_copy(copy); + let len = cmp::min(slice.len(), data.len()); - ptr::copy(data.as_ptr(), slice.as_mut_ptr(), len); + unsafe { + ptr::copy(data.as_ptr(), slice.as_mut_ptr(), len); + } Ok(*gas) }, - &mut OutputPolicy::Return(BytesRef::Flexible(ref mut vec)) => unsafe { + OutputPolicy::Return(BytesRef::Flexible(ref mut vec), ref mut copy) => { + handle_copy(copy); + vec.clear(); vec.reserve(data.len()); - ptr::copy(data.as_ptr(), vec.as_mut_ptr(), data.len()); - vec.set_len(data.len()); + unsafe { + ptr::copy(data.as_ptr(), vec.as_mut_ptr(), data.len()); + vec.set_len(data.len()); + } Ok(*gas) }, - &mut OutputPolicy::InitContract => { + OutputPolicy::InitContract(ref mut copy) => { let return_cost = U256::from(data.len()) * U256::from(self.schedule.create_data_gas); if return_cost > *gas { return match self.schedule.exceptional_failed_code_deposit { @@ -211,14 +225,16 @@ impl<'a> Ext for Externalities<'a> { false => Ok(*gas) } } + + handle_copy(copy); + let mut code = vec![]; code.reserve(data.len()); unsafe { ptr::copy(data.as_ptr(), code.as_mut_ptr(), data.len()); code.set_len(data.len()); } - let address = &self.origin_info.address; - self.state.init_code(address, code); + self.state.init_code(&self.origin_info.address, code); Ok(*gas - return_cost) } } @@ -226,7 +242,11 @@ impl<'a> Ext for Externalities<'a> { fn log(&mut self, topics: Vec, data: &[u8]) { let address = self.origin_info.address.clone(); - self.substate.logs.push(LogEntry::new(address, topics, data.to_vec())); + self.substate.logs.push(LogEntry { + address: address, + topics: topics, + data: data.to_vec() + }); } fn suicide(&mut self, refund_address: &Address) { @@ -297,12 +317,18 @@ mod tests { env_info: EnvInfo } + impl Default for TestSetup { + fn default() -> Self { + TestSetup::new() + } + } + impl TestSetup { - fn new() -> TestSetup { + fn new() -> Self { TestSetup { state: get_temp_state(), engine: get_test_spec().to_engine().unwrap(), - sub_state: Substate::new(), + sub_state: Substate::new(false), env_info: get_test_env_info() } } @@ -313,7 +339,7 @@ mod tests { let mut setup = TestSetup::new(); let state = setup.state.reference_mut(); - let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract); + let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None)); assert_eq!(ext.env_info().number, 100); } @@ -322,7 +348,7 @@ mod tests { fn can_return_block_hash_no_env() { let mut setup = TestSetup::new(); let state = setup.state.reference_mut(); - let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract); + let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None)); let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap()); @@ -341,7 +367,7 @@ mod tests { env_info.last_hashes.push(test_hash.clone()); } let state = setup.state.reference_mut(); - let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract); + let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None)); let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap()); @@ -353,7 +379,7 @@ mod tests { fn can_call_fail_empty() { let mut setup = TestSetup::new(); let state = setup.state.reference_mut(); - let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract); + let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None)); let mut output = vec![]; @@ -377,7 +403,7 @@ mod tests { let state = setup.state.reference_mut(); { - let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract); + let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None)); ext.log(log_topics, &log_data); } @@ -392,7 +418,7 @@ mod tests { let state = setup.state.reference_mut(); { - let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract); + let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None)); ext.suicide(&refund_account); } diff --git a/ethcore/src/extras.rs b/ethcore/src/extras.rs index b65d4ed7a..a7c82c37c 100644 --- a/ethcore/src/extras.rs +++ b/ethcore/src/extras.rs @@ -18,7 +18,7 @@ use util::*; use header::BlockNumber; -use rocksdb::{DB, Writable}; +use receipt::Receipt; /// Represents index of extra data in database #[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)] @@ -32,14 +32,16 @@ pub enum ExtrasIndex { /// Block log blooms index BlockLogBlooms = 3, /// Block blooms index - BlocksBlooms = 4 -} + BlocksBlooms = 4, + /// Block receipts index + BlockReceipts = 5, +} /// trait used to write Extras data to db pub trait ExtrasWritable { /// Write extra data to db fn put_extras(&self, hash: &K, value: &T) where - T: ExtrasIndexable + Encodable, + T: ExtrasIndexable + Encodable, K: ExtrasSliceConvertable; } @@ -56,16 +58,16 @@ pub trait ExtrasReadable { K: ExtrasSliceConvertable; } -impl ExtrasWritable for W where W: Writable { +impl ExtrasWritable for DBTransaction { fn put_extras(&self, hash: &K, value: &T) where - T: ExtrasIndexable + Encodable, + T: ExtrasIndexable + Encodable, K: ExtrasSliceConvertable { - + self.put(&hash.to_extras_slice(T::extras_index()), &encode(value)).unwrap() } } -impl ExtrasReadable for DB { +impl ExtrasReadable for Database { fn get_extras(&self, hash: &K) -> Option where T: ExtrasIndexable + Decodable, K: ExtrasSliceConvertable { @@ -210,7 +212,19 @@ impl Encodable for BlockLogBlooms { /// Neighboring log blooms on certain level pub struct BlocksBlooms { /// List of block blooms. - pub blooms: [H2048; 16] + pub blooms: [H2048; 16], +} + +impl Default for BlocksBlooms { + fn default() -> Self { + BlocksBlooms::new() + } +} + +impl BlocksBlooms { + pub fn new() -> Self { + BlocksBlooms { blooms: unsafe { ::std::mem::zeroed() }} + } } impl ExtrasIndexable for BlocksBlooms { @@ -292,3 +306,43 @@ impl Encodable for TransactionAddress { s.append(&self.index); } } + +/// Contains all block receipts. +#[derive(Clone)] +pub struct BlockReceipts { + pub receipts: Vec, +} + +impl BlockReceipts { + pub fn new(receipts: Vec) -> Self { + BlockReceipts { + receipts: receipts + } + } +} + +impl Decodable for BlockReceipts { + fn decode(decoder: &D) -> Result where D: Decoder { + Ok(BlockReceipts { + receipts: try!(Decodable::decode(decoder)) + }) + } +} + +impl Encodable for BlockReceipts { + fn rlp_append(&self, s: &mut RlpStream) { + s.append(&self.receipts); + } +} + +impl HeapSizeOf for BlockReceipts { + fn heap_size_of_children(&self) -> usize { + self.receipts.heap_size_of_children() + } +} + +impl ExtrasIndexable for BlockReceipts { + fn extras_index() -> ExtrasIndex { + ExtrasIndex::BlockReceipts + } +} diff --git a/ethcore/src/filter.rs b/ethcore/src/filter.rs new file mode 100644 index 000000000..9bfebf52f --- /dev/null +++ b/ethcore/src/filter.rs @@ -0,0 +1,230 @@ +// 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 filter + +use util::hash::*; +use util::sha3::*; +use client::BlockId; +use log_entry::LogEntry; + +/// Blockchain Filter. +pub struct Filter { + /// Blockchain will be searched from this block. + pub from_block: BlockId, + + /// Till this block. + pub to_block: BlockId, + + /// Search addresses. + /// + /// If None, match all. + /// If specified, log must be produced by one of these addresses. + pub address: Option>, + + /// Search topics. + /// + /// If None, match all. + /// If specified, log must contain one of these topics. + pub topics: [Option>; 4], +} + +impl Clone for Filter { + fn clone(&self) -> Self { + let mut topics = [None, None, None, None]; + for i in 0..4 { + topics[i] = self.topics[i].clone(); + } + + Filter { + from_block: self.from_block.clone(), + to_block: self.to_block.clone(), + address: self.address.clone(), + topics: topics + } + } +} + +impl Filter { + /// Returns combinations of each address and topic. + pub fn bloom_possibilities(&self) -> Vec { + let blooms = match self.address { + Some(ref addresses) if !addresses.is_empty() => + addresses.iter().map(|ref address| { + let mut bloom = H2048::new(); + bloom.shift_bloomed(&address.sha3()); + bloom + }).collect(), + _ => vec![H2048::new()] + }; + + self.topics.iter().fold(blooms, | bs, topic | match *topic { + None => bs, + Some(ref topics) => bs.into_iter().flat_map(|bloom| { + topics.into_iter().map(|topic| { + let mut b = bloom.clone(); + b.shift_bloomed(&topic.sha3()); + b + }).collect::>() + }).collect() + }) + } + + /// Returns true if given log entry matches filter. + pub fn matches(&self, log: &LogEntry) -> bool { + let matches = match self.address { + Some(ref addresses) if !addresses.is_empty() => addresses.iter().any(|address| &log.address == address), + _ => true + }; + + matches && self.topics.iter().enumerate().all(|(i, topic)| match *topic { + Some(ref topics) if !topics.is_empty() => topics.iter().any(|topic| log.topics.get(i) == Some(topic)), + _ => true + }) + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + use util::hash::*; + use filter::Filter; + use client::BlockId; + use log_entry::LogEntry; + + #[test] + fn test_bloom_possibilities_none() { + let none_filter = Filter { + from_block: BlockId::Earliest, + to_block: BlockId::Latest, + address: None, + topics: [None, None, None, None] + }; + + let possibilities = none_filter.bloom_possibilities(); + assert_eq!(possibilities.len(), 1); + assert!(possibilities[0].is_zero()) + } + + // block 399849 + #[test] + fn test_bloom_possibilities_single_address_and_topic() { + let filter = Filter { + from_block: BlockId::Earliest, + to_block: BlockId::Latest, + address: Some(vec![Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap()]), + topics: [ + Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]), + None, None, None + ] + }; + + let possibilities = filter.bloom_possibilities(); + assert_eq!(possibilities, vec![H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()]); + } + + #[test] + fn test_bloom_possibilities_single_address_and_many_topics() { + let filter = Filter { + from_block: BlockId::Earliest, + to_block: BlockId::Latest, + address: Some(vec![Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap()]), + topics: [ + Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]), + Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]), + None, None + ] + }; + + let possibilities = filter.bloom_possibilities(); + assert_eq!(possibilities, vec![H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()]); + } + + #[test] + fn test_bloom_possibilites_multiple_addresses_and_topics() { + let filter = Filter { + from_block: BlockId::Earliest, + to_block: BlockId::Latest, + address: Some(vec![ + Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap(), + Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap(), + ]), + topics: [ + Some(vec![ + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(), + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap() + ]), + Some(vec![ + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(), + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap() + ]), + Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]), + None + ] + }; + + // number of possibilites should be equal 2 * 2 * 2 * 1 = 8 + let possibilities = filter.bloom_possibilities(); + assert_eq!(possibilities.len(), 8); + assert_eq!(possibilities[0], H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000004000000004000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()); + } + + #[test] + fn test_filter_matches() { + let filter = Filter { + from_block: BlockId::Earliest, + to_block: BlockId::Latest, + address: Some(vec![Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap()]), + topics: [ + Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap()]), + Some(vec![H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23fa").unwrap()]), + None, None + ] + }; + + let entry0 = LogEntry { + address: Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap(), + topics: vec![ + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(), + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23fa").unwrap(), + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(), + ], + data: vec![] + }; + + let entry1 = LogEntry { + address: Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5e").unwrap(), + topics: vec![ + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(), + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23fa").unwrap(), + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(), + ], + data: vec![] + }; + + let entry2 = LogEntry { + address: Address::from_str("b372018f3be9e171df0581136b59d2faf73a7d5d").unwrap(), + topics: vec![ + H256::from_str("ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9").unwrap(), + ], + data: vec![] + }; + + assert_eq!(filter.matches(&entry0), true); + assert_eq!(filter.matches(&entry1), false); + assert_eq!(filter.matches(&entry2), false); + } +} diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index 6ee682544..1e1a54d57 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -29,7 +29,7 @@ pub type BlockNumber = u64; /// which is non-specific. /// /// Doesn't do all that much on its own. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq)] pub struct Header { // TODO: make all private. /// Parent hash. @@ -70,6 +70,25 @@ pub struct Header { pub bare_hash: RefCell>, } +impl PartialEq for Header { + fn eq(&self, c: &Header) -> bool { + self.parent_hash == c.parent_hash && + self.timestamp == c.timestamp && + self.number == c.number && + self.author == c.author && + self.transactions_root == c.transactions_root && + self.uncles_hash == c.uncles_hash && + self.extra_data == c.extra_data && + self.state_root == c.state_root && + self.receipts_root == c.receipts_root && + self.log_bloom == c.log_bloom && + self.gas_used == c.gas_used && + self.gas_limit == c.gas_limit && + self.difficulty == c.difficulty && + self.seal == c.seal + } +} + impl Default for Header { fn default() -> Self { Header { @@ -102,10 +121,12 @@ impl Header { Self::default() } - /// Get the number field of the header. - pub fn number(&self) -> BlockNumber { self.number } + /// Get the parent_hash field of the header. + pub fn parent_hash(&self) -> &H256 { &self.parent_hash } /// Get the timestamp field of the header. pub fn timestamp(&self) -> u64 { self.timestamp } + /// Get the number field of the header. + pub fn number(&self) -> BlockNumber { self.number } /// Get the author field of the header. pub fn author(&self) -> &Address { &self.author } @@ -127,11 +148,13 @@ impl Header { // TODO: seal_at, set_seal_at &c. /// Set the number field of the header. - pub fn set_number(&mut self, a: BlockNumber) { self.number = a; self.note_dirty(); } + pub fn set_parent_hash(&mut self, a: H256) { self.parent_hash = a; self.note_dirty(); } /// Set the timestamp field of the header. pub fn set_timestamp(&mut self, a: u64) { self.timestamp = a; self.note_dirty(); } /// Set the timestamp field of the header to the current time. - pub fn set_timestamp_now(&mut self) { self.timestamp = now_utc().to_timespec().sec as u64; self.note_dirty(); } + pub fn set_timestamp_now(&mut self, but_later_than: u64) { self.timestamp = max(now_utc().to_timespec().sec as u64, but_later_than + 1); self.note_dirty(); } + /// Set the number field of the header. + pub fn set_number(&mut self, a: BlockNumber) { self.number = a; self.note_dirty(); } /// Set the author field of the header. pub fn set_author(&mut self, a: Address) { if a != self.author { self.author = a; self.note_dirty(); } } diff --git a/ethcore/src/json_tests/chain.rs b/ethcore/src/json_tests/chain.rs index 6a9f84073..a2e6a5659 100644 --- a/ethcore/src/json_tests/chain.rs +++ b/ethcore/src/json_tests/chain.rs @@ -15,18 +15,20 @@ // along with Parity. If not, see . use super::test_common::*; -use client::{BlockChainClient,Client}; -use pod_state::*; +use client::{BlockChainClient, Client, ClientConfig}; 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 { @@ -38,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(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() { + let client = Client::new(ClientConfig::default(), spec, temp.as_path(), IoChannel::disconnected()).unwrap(); + 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/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index b08257a92..dbb9bb6ab 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -75,7 +75,7 @@ impl<'a> TestExt<'a> { depth: usize, origin_info: OriginInfo, substate: &'a mut Substate, - output: OutputPolicy<'a>, + output: OutputPolicy<'a, 'a>, address: Address) -> Self { TestExt { contract_address: contract_address(&address, &state.nonce(&address)), @@ -227,19 +227,21 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec { let out_of_gas = test.find("callcreates").map(|_calls| { }).is_none(); - let mut substate = Substate::new(); + let mut substate = Substate::new(false); let mut output = vec![]; // execute let (res, callcreates) = { - let mut ex = TestExt::new(&mut state, - &info, - &engine, - 0, - OriginInfo::from(¶ms), - &mut substate, - OutputPolicy::Return(BytesRef::Flexible(&mut output)), - params.address.clone()); + let mut ex = TestExt::new( + &mut state, + &info, + &engine, + 0, + OriginInfo::from(¶ms), + &mut substate, + OutputPolicy::Return(BytesRef::Flexible(&mut output), None), + params.address.clone() + ); let evm = engine.vm_factory().create(); let res = evm.exec(params, &mut ex); (res, ex.callcreates) diff --git a/ethcore/src/json_tests/state.rs b/ethcore/src/json_tests/state.rs index b5f28444a..4c001007a 100644 --- a/ethcore/src/json_tests/state.rs +++ b/ethcore/src/json_tests/state.rs @@ -69,7 +69,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { let mut state = state_result.reference_mut(); state.populate_from(pre); state.commit(); - let res = state.apply(&env, engine.deref(), &t); + let res = state.apply(&env, engine.deref(), &t, false); if fail_unless(state.root() == &post_state_root) { println!("!!! {}: State mismatch (got: {}, expect: {}):", name, state.root(), post_state_root); @@ -80,9 +80,9 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { } if let Ok(r) = res { - if fail_unless(logs == r.logs) { + if fail_unless(logs == r.receipt.logs) { println!("!!! {}: Logs mismatch:", name); - println!("Got:\n{:?}", r.logs); + println!("Got:\n{:?}", r.receipt.logs); println!("Expect:\n{:?}", logs); } } @@ -115,7 +115,7 @@ declare_test!{StateTests_stSolidityTest, "StateTests/stSolidityTest"} declare_test!{StateTests_stSpecialTest, "StateTests/stSpecialTest"} declare_test!{StateTests_stSystemOperationsTest, "StateTests/stSystemOperationsTest"} declare_test!{StateTests_stTransactionTest, "StateTests/stTransactionTest"} -//declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"} +declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"} declare_test!{StateTests_stWalletTest, "StateTests/stWalletTest"} diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 4cca74319..f8fb223db 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -15,18 +15,18 @@ // along with Parity. If not, see . #![warn(missing_docs)] -#![feature(cell_extras)] -#![feature(augmented_assignments)] -#![feature(plugin)] -// Clippy -#![plugin(clippy)] -// TODO [todr] not really sure -#![allow(needless_range_loop)] -// Shorter than if-else -#![allow(match_bool)] -// Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. -#![allow(clone_on_copy)] +#![cfg_attr(feature="dev", feature(plugin))] +#![cfg_attr(feature="dev", plugin(clippy))] +// Clippy config +// TODO [todr] not really sure +#![cfg_attr(feature="dev", allow(needless_range_loop))] +// Shorter than if-else +#![cfg_attr(feature="dev", allow(match_bool))] +// Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. +#![cfg_attr(feature="dev", allow(clone_on_copy))] +// In most cases it expresses function flow better +#![cfg_attr(feature="dev", allow(if_not_else))] //! Ethcore library //! @@ -42,23 +42,17 @@ //! - Ubuntu 14.04 and later: //! //! ```bash -//! # install rocksdb -//! add-apt-repository "deb http://ppa.launchpad.net/giskou/librocksdb/ubuntu trusty main" -//! apt-get update -//! apt-get install -y --force-yes librocksdb //! //! # install multirust //! curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes //! -//! # install nightly and make it default -//! multirust update nightly && multirust default nightly -//! //! # export rust LIBRARY_PATH //! export LIBRARY_PATH=/usr/local/lib //! //! # download and build parity //! git clone https://github.com/ethcore/parity //! cd parity +//! multirust override beta //! cargo build --release //! ``` //! @@ -67,18 +61,15 @@ //! ```bash //! # install rocksdb && multirust //! brew update -//! brew install rocksdb //! brew install multirust //! -//! # install nightly and make it default -//! multirust update nightly && multirust default nightly -//! //! # export rust LIBRARY_PATH //! export LIBRARY_PATH=/usr/local/lib //! //! # download and build parity //! git clone https://github.com/ethcore/parity //! cd parity +//! multirust override beta //! cargo build --release //! ``` @@ -86,36 +77,38 @@ #[macro_use] extern crate ethcore_util as util; #[macro_use] extern crate lazy_static; extern crate rustc_serialize; -extern crate rocksdb; -extern crate heapsize; +#[macro_use] extern crate heapsize; extern crate crypto; 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; pub mod block; -pub mod blockchain; pub mod block_queue; pub mod client; pub mod error; pub mod ethereum; +pub mod filter; pub mod header; pub mod service; +pub mod log_entry; +pub mod trace; 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 log_entry; mod env_info; mod pod_account; -mod pod_state; mod account_diff; mod state_diff; mod engine; @@ -125,11 +118,13 @@ mod account_db; mod action_params; mod null_engine; mod builtin; +mod chainfilter; mod extras; mod substate; mod executive; mod externalities; mod verification; +mod blockchain; #[cfg(test)] mod tests; diff --git a/ethcore/src/log_entry.rs b/ethcore/src/log_entry.rs index ee73b1ad1..63e07730e 100644 --- a/ethcore/src/log_entry.rs +++ b/ethcore/src/log_entry.rs @@ -14,8 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Block log. + use util::*; use basic_types::LogBloom; +use header::BlockNumber; /// A record of execution for a `LOG` operation. #[derive(Default, Debug, Clone, PartialEq, Eq)] @@ -37,16 +40,25 @@ impl Encodable for LogEntry { } } -impl LogEntry { - /// Create a new log entry. - pub fn new(address: Address, topics: Vec, data: Bytes) -> LogEntry { - LogEntry { - address: address, - topics: topics, - data: data - } +impl Decodable for LogEntry { + fn decode(decoder: &D) -> Result where D: Decoder { + let d = decoder.as_rlp(); + let entry = LogEntry { + address: try!(d.val_at(0)), + topics: try!(d.val_at(1)), + data: try!(d.val_at(2)), + }; + Ok(entry) } +} +impl HeapSizeOf for LogEntry { + fn heap_size_of_children(&self) -> usize { + self.topics.heap_size_of_children() + self.data.heap_size_of_children() + } +} + +impl LogEntry { /// Calculates the bloom of this log entry. pub fn bloom(&self) -> LogBloom { self.topics.iter().fold(LogBloom::from_bloomed(&self.address.sha3()), |b, t| b.with_bloomed(&t.sha3())) @@ -65,6 +77,31 @@ impl FromJson for LogEntry { } } +/// Log localized in a blockchain. +#[derive(Default, Debug, PartialEq, Clone)] +pub struct LocalizedLogEntry { + /// Plain log entry. + pub entry: LogEntry, + /// Block in which this log was created. + pub block_hash: H256, + /// Block number. + pub block_number: BlockNumber, + /// Hash of transaction in which this log was created. + pub transaction_hash: H256, + /// Index of transaction within block. + pub transaction_index: usize, + /// Log position in the block. + pub log_index: usize, +} + +impl Deref for LocalizedLogEntry { + type Target = LogEntry; + + fn deref(&self) -> &Self::Target { + &self.entry + } +} + #[cfg(test)] mod tests { use util::*; @@ -74,7 +111,11 @@ mod tests { fn test_empty_log_bloom() { let bloom = H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); - let log = LogEntry::new(address, vec![], vec![]); + let log = LogEntry { + address: address, + topics: vec![], + data: vec![] + }; assert_eq!(log.bloom(), bloom); } } diff --git a/ethcore/src/null_engine.rs b/ethcore/src/null_engine.rs index af7255617..99231add4 100644 --- a/ethcore/src/null_engine.rs +++ b/ethcore/src/null_engine.rs @@ -41,7 +41,16 @@ impl Engine for NullEngine { fn vm_factory(&self) -> &Factory { &self.factory } + fn name(&self) -> &str { "NullEngine" } + fn spec(&self) -> &Spec { &self.spec } - fn schedule(&self, _env_info: &EnvInfo) -> Schedule { Schedule::new_frontier() } + + fn schedule(&self, env_info: &EnvInfo) -> Schedule { + if env_info.number < self.u64_param("frontierCompatibilityModeLimit") { + Schedule::new_frontier() + } else { + Schedule::new_homestead() + } + } } 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 5fc1a318b..2fbd3f14c 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)] @@ -39,7 +40,7 @@ impl Receipt { Receipt { state_root: state_root, gas_used: gas_used, - log_bloom: logs.iter().fold(LogBloom::new(), |mut b, l| { b |= &l.bloom(); b }), + log_bloom: logs.iter().fold(LogBloom::new(), |mut b, l| { b = &b | &l.bloom(); b }), //TODO: use |= operator logs: logs, } } @@ -55,6 +56,45 @@ impl Encodable for Receipt { } } +impl Decodable for Receipt { + fn decode(decoder: &D) -> Result where D: Decoder { + let d = decoder.as_rlp(); + let receipt = Receipt { + state_root: try!(d.val_at(0)), + gas_used: try!(d.val_at(1)), + log_bloom: try!(d.val_at(2)), + logs: try!(d.val_at(3)), + }; + Ok(receipt) + } +} + +impl HeapSizeOf for Receipt { + fn heap_size_of_children(&self) -> usize { + self.logs.heap_size_of_children() + } +} + +/// Receipt with additional info. +#[derive(Debug, Clone, PartialEq)] +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() { @@ -62,11 +102,11 @@ fn test_basic() { let r = Receipt::new( x!("2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee"), x!(0x40cae), - vec![LogEntry::new( - x!("dcf421d093428b096ca501a7cd1a740855a7976f"), - vec![], - vec![0u8; 32] - )] + vec![LogEntry { + address: x!("dcf421d093428b096ca501a7cd1a740855a7976f"), + topics: vec![], + data: vec![0u8; 32] + }] ); assert_eq!(&encode(&r)[..], &expected[..]); } diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index 5e68efae9..95a891198 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -20,13 +20,24 @@ use util::*; use util::panics::*; use spec::Spec; use error::*; -use client::Client; +use client::{Client, ClientConfig}; /// Message type for external and internal events #[derive(Clone)] pub enum SyncMessage { /// New block has been imported into the blockchain - NewChainBlock(Bytes), //TODO: use Cow + NewChainBlocks { + /// Hashes of blocks imported to blockchain + imported: Vec, + /// Hashes of blocks not imported to blockchain (because were invalid) + invalid: Vec, + /// Hashes of blocks that were removed from canonical chain + retracted: Vec, + /// Hashes of blocks that are now included in cannonical chain + enacted: Vec, + }, + /// Best Block Hash in chain has been changed + NewChainHead, /// A block is ready BlockVerified, } @@ -43,14 +54,14 @@ pub struct ClientService { impl ClientService { /// Start the service in a separate thread. - pub fn start(spec: Spec, net_config: NetworkConfiguration, db_path: &Path) -> Result { + pub fn start(config: ClientConfig, spec: Spec, net_config: NetworkConfiguration, db_path: &Path) -> Result { let panic_handler = PanicHandler::new_in_arc(); let mut net_service = try!(NetworkService::start(net_config)); panic_handler.forward_from(&net_service); info!("Starting {}", net_service.host_info()); info!("Configured for {} using {} engine", spec.name, spec.engine_name); - let client = try!(Client::new(spec, db_path, net_service.io().channel())); + let client = try!(Client::new(config, spec, db_path, net_service.io().channel())); panic_handler.forward_from(client.deref()); let client_io = Arc::new(ClientIoHandler { client: client.clone() @@ -110,12 +121,11 @@ impl IoHandler for ClientIoHandler { } } - #[allow(match_ref_pats)] - #[allow(single_match)] + #[cfg_attr(feature="dev", allow(single_match))] fn message(&self, io: &IoContext, net_message: &NetSyncMessage) { - if let &UserMessage(ref message) = net_message { - match message { - &SyncMessage::BlockVerified => { + if let UserMessage(ref message) = *net_message { + match *message { + SyncMessage::BlockVerified => { self.client.import_verified_blocks(&io.channel()); }, _ => {}, // ignore other messages @@ -129,12 +139,14 @@ mod tests { use super::*; use tests::helpers::*; use util::network::*; + use devtools::*; + use client::ClientConfig; #[test] fn it_can_be_started() { let spec = get_test_spec(); let temp_path = RandomTempPath::new(); - let service = ClientService::start(spec, NetworkConfiguration::new(), &temp_path.as_path()); + let service = ClientService::start(ClientConfig::default(), spec, NetworkConfiguration::new_local(), &temp_path.as_path()); assert!(service.is_ok()); } } 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 88% rename from ethcore/src/spec.rs rename to ethcore/src/spec/spec.rs index 67269d334..f97d8c8dc 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. @@ -58,6 +60,8 @@ pub struct Spec { /// Known nodes on the network in enode format. pub nodes: Vec, + /// Network ID + pub network_id: U256, /// Parameters concerning operation of the specific engine we're using. /// Maps the parameter name to an RLP-encoded value. @@ -97,14 +101,14 @@ pub struct Spec { genesis_state: PodState, } -#[allow(wrong_self_convention)] // because to_engine(self) should be to_engine(&self) +#[cfg_attr(feature="dev", allow(wrong_self_convention))] // because to_engine(self) should be to_engine(&self) impl Spec { /// Convert this object into a boxed Engine of the right underlying type. // TODO avoid this hard-coded nastiness - use dynamic-linked plugin framework instead. 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())) } } @@ -120,6 +124,9 @@ impl Spec { /// Get the known knodes of the network in enode format. pub fn nodes(&self) -> &Vec { &self.nodes } + /// Get the configured Network ID. + pub fn network_id(&self) -> U256 { self.network_id } + /// Get the header of the genesis block. pub fn genesis_header(&self) -> Header { Header { @@ -131,7 +138,7 @@ impl Spec { uncles_hash: RlpStream::new_list(0).out().sha3(), extra_data: self.extra_data.clone(), state_root: self.state_root().clone(), - receipts_root: self.receipts_root.clone(), + receipts_root: self.receipts_root.clone(), log_bloom: H2048::new().clone(), gas_used: self.gas_used.clone(), gas_limit: self.gas_limit.clone(), @@ -177,7 +184,7 @@ impl Spec { ) } }; - + self.parent_hash = H256::from_json(&genesis["parentHash"]); self.transactions_root = genesis.find("transactionsTrie").and_then(|_| Some(H256::from_json(&genesis["transactionsTrie"]))).unwrap_or(SHA3_NULL_RLP.clone()); self.receipts_root = genesis.find("receiptTrie").and_then(|_| Some(H256::from_json(&genesis["receiptTrie"]))).unwrap_or(SHA3_NULL_RLP.clone()); @@ -192,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; @@ -244,12 +277,13 @@ impl FromJson for Spec { ) } }; - + Spec { name: json.find("name").map_or("unknown", |j| j.as_string().unwrap()).to_owned(), engine_name: json["engineName"].as_string().unwrap().to_owned(), engine_params: json_to_rlp_map(&json["params"]), nodes: nodes, + network_id: U256::from_str(&json["params"]["networkID"].as_string().unwrap()[2..]).unwrap(), builtins: builtins, parent_hash: H256::from_str(&genesis["parentHash"].as_string().unwrap()[2..]).unwrap(), author: Address::from_str(&genesis["author"].as_string().unwrap()[2..]).unwrap(), @@ -272,7 +306,7 @@ impl Spec { /// Ensure that the given state DB has the trie nodes in for the genesis state. pub fn ensure_db_good(&self, db: &mut HashDB) -> bool { if !db.contains(&self.state_root()) { - let mut root = H256::new(); + let mut root = H256::new(); { let mut t = SecTrieDBMut::new(db, &mut root); for (address, account) in self.genesis_state.get().iter() { @@ -298,7 +332,10 @@ 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")) } + + /// Create a new Spec which conforms to the Morden chain except that it's a NullEngine consensus. + pub fn new_homestead_test() -> Spec { Self::from_json_utf8(include_bytes!("../../res/null_homestead_morden.json")) } } #[cfg(test)] diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 00886b89c..21b0ad6ed 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -26,12 +26,20 @@ use pod_account::*; use pod_state::PodState; //use state_diff::*; // TODO: uncomment once to_pod() works correctly. +/// Used to return information about an `State::apply` operation. +pub struct ApplyOutcome { + /// The receipt for the applied transaction. + pub receipt: Receipt, + /// The trace for the applied transaction, if None if tracing is disabled. + pub trace: Option, +} + /// Result type for the execution ("application") of a transaction. -pub type ApplyResult = Result; +pub type ApplyResult = Result; /// Representation of the entire state of all accounts in the system. pub struct State { - db: JournalDB, + db: Box, root: H256, cache: RefCell>>, snapshots: RefCell>>>>, @@ -41,11 +49,11 @@ pub struct State { impl State { /// Creates new state with empty state root #[cfg(test)] - pub fn new(mut db: JournalDB, account_start_nonce: U256) -> State { + pub fn new(mut db: Box, account_start_nonce: U256) -> State { let mut root = H256::new(); { // init trie and reset root too null - let _ = SecTrieDBMut::new(&mut db, &mut root); + let _ = SecTrieDBMut::new(db.as_hashdb_mut(), &mut root); } State { @@ -58,10 +66,10 @@ impl State { } /// Creates new state with existing state root - pub fn from_existing(db: JournalDB, root: H256, account_start_nonce: U256) -> State { + pub fn from_existing(db: Box, root: H256, account_start_nonce: U256) -> State { { // trie should panic! if root does not exist - let _ = SecTrieDB::new(&db, &root); + let _ = SecTrieDB::new(db.as_hashdb(), &root); } State { @@ -126,7 +134,7 @@ impl State { } /// Destroy the current object and return root and database. - pub fn drop(self) -> (H256, JournalDB) { + pub fn drop(self) -> (H256, Box) { (self.root, self.db) } @@ -138,7 +146,7 @@ impl State { /// Create a new contract at address `contract`. If there is already an account at the address /// it will have its code reset, ready for `init_code()`. pub fn new_contract(&mut self, contract: &Address, balance: U256) { - self.insert_cache(&contract, Some(Account::new_contract(balance))); + self.insert_cache(&contract, Some(Account::new_contract(balance, self.account_start_nonce))); } /// Remove an existing account. @@ -148,7 +156,7 @@ impl State { /// Determine whether an account exists. pub fn exists(&self, a: &Address) -> bool { - self.cache.borrow().get(&a).unwrap_or(&None).is_some() || SecTrieDB::new(&self.db, &self.root).contains(&a) + self.cache.borrow().get(&a).unwrap_or(&None).is_some() || SecTrieDB::new(self.db.as_hashdb(), &self.root).contains(&a) } /// Get the balance of account `a`. @@ -163,7 +171,7 @@ impl State { /// Mutate storage of account `address` so that it is `value` for `key`. pub fn storage_at(&self, address: &Address, key: &H256) -> H256 { - self.get(address, false).as_ref().map_or(H256::new(), |a|a.storage_at(&AccountDB::new(&self.db, address), key)) + self.get(address, false).as_ref().map_or(H256::new(), |a|a.storage_at(&AccountDB::new(self.db.as_hashdb(), address), key)) } /// Mutate storage of account `a` so that it is `value` for `key`. @@ -204,27 +212,27 @@ impl State { /// Initialise the code of account `a` so that it is `value` for `key`. /// NOTE: Account should have been created with `new_contract`. pub fn init_code(&mut self, a: &Address, code: Bytes) { - self.require_or_from(a, true, || Account::new_contract(U256::from(0u8)), |_|{}).init_code(code); + self.require_or_from(a, true, || Account::new_contract(x!(0), self.account_start_nonce), |_|{}).init_code(code); } /// Execute a given transaction. /// This will change the state accordingly. - pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &SignedTransaction) -> ApplyResult { + pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &SignedTransaction, tracing: bool) -> ApplyResult { // let old = self.to_pod(); - let e = try!(Executive::new(self, env_info, engine).transact(t)); + let e = try!(Executive::new(self, env_info, engine).transact(t, tracing)); // TODO uncomment once to_pod() works correctly. // trace!("Applied transaction. Diff:\n{}\n", StateDiff::diff_pod(&old, &self.to_pod())); self.commit(); let receipt = Receipt::new(self.root().clone(), e.cumulative_gas_used, e.logs); // trace!("Transaction receipt: {:?}", receipt); - Ok(receipt) + Ok(ApplyOutcome{receipt: receipt, trace: e.trace}) } /// Commit accounts to SecTrieDBMut. This is similar to cpp-ethereum's dev::eth::commit. /// `accounts` is mutable because we may need to commit the code or storage and record that. - #[allow(match_ref_pats)] + #[cfg_attr(feature="dev", allow(match_ref_pats))] pub fn commit_into(db: &mut HashDB, root: &mut H256, accounts: &mut HashMap>) { // first, commit the sub trees. // TODO: is this necessary or can we dispense with the `ref mut a` for just `a`? @@ -253,7 +261,7 @@ impl State { /// Commits our cached account changes into the trie. pub fn commit(&mut self) { assert!(self.snapshots.borrow().is_empty()); - Self::commit_into(&mut self.db, &mut self.root, self.cache.borrow_mut().deref_mut()); + Self::commit_into(self.db.as_hashdb_mut(), &mut self.root, self.cache.borrow_mut().deref_mut()); } #[cfg(test)] @@ -282,30 +290,30 @@ impl State { /// Pull account `a` in our cache from the trie DB and return it. /// `require_code` requires that the code be cached, too. - fn get(&self, a: &Address, require_code: bool) -> Ref> { + fn get<'a>(&'a self, a: &Address, require_code: bool) -> &'a Option { let have_key = self.cache.borrow().contains_key(a); if !have_key { - self.insert_cache(a, SecTrieDB::new(&self.db, &self.root).get(&a).map(Account::from_rlp)) + self.insert_cache(a, SecTrieDB::new(self.db.as_hashdb(), &self.root).get(&a).map(Account::from_rlp)) } if require_code { if let Some(ref mut account) = self.cache.borrow_mut().get_mut(a).unwrap().as_mut() { - account.cache_code(&AccountDB::new(&self.db, a)); + account.cache_code(&AccountDB::new(self.db.as_hashdb(), a)); } } - Ref::map(self.cache.borrow(), |m| m.get(a).unwrap()) + unsafe { ::std::mem::transmute(self.cache.borrow().get(a).unwrap()) } } /// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too. - fn require(&self, a: &Address, require_code: bool) -> RefMut { + fn require<'a>(&'a self, a: &Address, require_code: bool) -> &'a mut Account { self.require_or_from(a, require_code, || Account::new_basic(U256::from(0u8), self.account_start_nonce), |_|{}) } /// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too. /// If it doesn't exist, make account equal the evaluation of `default`. - fn require_or_from Account, G: FnOnce(&mut Account)>(&self, a: &Address, require_code: bool, default: F, not_default: G) -> RefMut { + fn require_or_from<'a, F: FnOnce() -> Account, G: FnOnce(&mut Account)>(&self, a: &Address, require_code: bool, default: F, not_default: G) -> &'a mut Account { let have_key = self.cache.borrow().contains_key(a); if !have_key { - self.insert_cache(a, SecTrieDB::new(&self.db, &self.root).get(&a).map(Account::from_rlp)) + self.insert_cache(a, SecTrieDB::new(self.db.as_hashdb(), &self.root).get(&a).map(Account::from_rlp)) } else { self.note_cache(a); } @@ -316,13 +324,12 @@ impl State { not_default(self.cache.borrow_mut().get_mut(a).unwrap().as_mut().unwrap()); } - let b = self.cache.borrow_mut(); - RefMut::map(b, |m| m.get_mut(a).unwrap().as_mut().map(|account| { + unsafe { ::std::mem::transmute(self.cache.borrow_mut().get_mut(a).unwrap().as_mut().map(|account| { if require_code { - account.cache_code(&AccountDB::new(&self.db, a)); + account.cache_code(&AccountDB::new(self.db.as_hashdb(), a)); } account - }).unwrap()) + }).unwrap()) } } } @@ -336,12 +343,671 @@ impl fmt::Debug for State { mod tests { use super::*; -use util::hash::*; +use util::common::*; use util::trie::*; use util::rlp::*; -use util::uint::*; use account::*; use tests::helpers::*; +use devtools::*; +use evm::factory::*; +use env_info::*; +use spec::*; +use transaction::*; +use util::log::init_log; +use trace::*; + +#[test] +fn should_apply_create_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Create, + value: x!(100), + data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555").unwrap(), + }.sign(&"".sha3()); + + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Create(TraceCreate { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + value: x!(100), + gas: x!(77412), + init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], + result: Some((x!(3224), x!("8988167e088c87cd314df6d3c2b83da5acb93ace"), vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53])) + }), + subs: vec![] + }); + + assert_eq!(result.trace, expected_trace); +} + +#[test] +fn should_trace_failed_create_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Create, + value: x!(100), + data: FromHex::from_hex("5b600056").unwrap(), + }.sign(&"".sha3()); + + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Create(TraceCreate { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + value: x!(100), + gas: x!(78792), + init: vec![91, 96, 0, 86], + result: None + }), + subs: vec![] + }); + + assert_eq!(result.trace, expected_trace); +} + +#[test] +fn should_trace_call_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(100), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("6000").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: Some((x!(3), vec![])) + }), + subs: vec![] + }); + + assert_eq!(result.trace, expected_trace); +} + +#[test] +fn should_trace_basic_call_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(100), + data: vec![], + }.sign(&"".sha3()); + + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: Some((x!(0), vec![])) + }), + subs: vec![] + }); + + assert_eq!(result.trace, expected_trace); +} + +#[test] +fn should_not_trace_call_transaction_to_builtin() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = Spec::new_test().to_engine().unwrap(); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0x1)), + value: x!(0), + data: vec![], + }.sign(&"".sha3()); + + let result = state.apply(&info, engine.deref(), &t, true).unwrap(); + + assert_eq!(result.trace, None); +} + +#[test] +fn should_not_trace_subcall_transaction_to_builtin() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = Spec::new_test().to_engine().unwrap(); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(0), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("600060006000600060006001610be0f1").unwrap()); + let result = state.apply(&info, engine.deref(), &t, true).unwrap(); + + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(0), + gas: x!(79000), + input: vec![], + result: Some((x!(28061), vec![])) + }), + subs: vec![] + }); + assert_eq!(result.trace, expected_trace); +} + +#[test] +fn should_not_trace_callcode() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = Spec::new_test().to_engine().unwrap(); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(0), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b611000f2").unwrap()); + state.init_code(&x!(0xb), FromHex::from_hex("6000").unwrap()); + let result = state.apply(&info, engine.deref(), &t, true).unwrap(); + + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(0), + gas: x!(79000), + input: vec![], + result: Some((x!(64), vec![])) + }), + subs: vec![] + }); + assert_eq!(result.trace, expected_trace); +} + +#[test] +fn should_not_trace_delegatecall() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + info.number = 0x789b0; + let engine = Spec::new_test().to_engine().unwrap(); + + println!("schedule.have_delegate_call: {:?}", engine.schedule(&info).have_delegate_call); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(0), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("6000600060006000600b618000f4").unwrap()); + state.init_code(&x!(0xb), FromHex::from_hex("6000").unwrap()); + let result = state.apply(&info, engine.deref(), &t, true).unwrap(); + + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(0), + gas: x!(79000), + input: vec![], + result: Some((x!(61), vec![])) + }), + subs: vec![] + }); + assert_eq!(result.trace, expected_trace); +} + +#[test] +fn should_trace_failed_call_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(100), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("5b600056").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: None + }), + subs: vec![] + }); + + println!("trace: {:?}", result.trace); + + assert_eq!(result.trace, expected_trace); +} + +#[test] +fn should_trace_call_with_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(100), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&x!(0xb), FromHex::from_hex("6000").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: Some((x!(69), vec![])) + }), + subs: vec![Trace { + depth: 1, + action: TraceAction::Call(TraceCall { + from: x!(0xa), + to: x!(0xb), + value: x!(0), + gas: x!(78934), + input: vec![], + result: Some((x!(3), vec![])) + }), + subs: vec![] + }] + }); + + assert_eq!(result.trace, expected_trace); +} + +#[test] +fn should_trace_call_with_basic_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(100), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006045600b6000f1").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: Some((x!(31761), vec![])) + }), + subs: vec![Trace { + depth: 1, + action: TraceAction::Call(TraceCall { + from: x!(0xa), + to: x!(0xb), + value: x!(69), + gas: x!(2300), + input: vec![], + result: Some((x!(0), vec![])) + }), + subs: vec![] + }] + }); + + assert_eq!(result.trace, expected_trace); +} + +#[test] +fn should_not_trace_call_with_invalid_basic_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(100), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()); // not enough funds. + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: Some((x!(31761), vec![])) + }), + subs: vec![] + }); + + assert_eq!(result.trace, expected_trace); +} + +#[test] +fn should_trace_failed_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(100), + data: vec![],//600480600b6000396000f35b600056 + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&x!(0xb), FromHex::from_hex("5b600056").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: Some((x!(79000), vec![])) + }), + subs: vec![Trace { + depth: 1, + action: TraceAction::Call(TraceCall { + from: x!(0xa), + to: x!(0xb), + value: x!(0), + gas: x!(78934), + input: vec![], + result: None + }), + subs: vec![] + }] + }); + + assert_eq!(result.trace, expected_trace); +} + +#[test] +fn should_trace_call_with_subcall_with_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(100), + data: vec![], + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&x!(0xb), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap()); + state.init_code(&x!(0xc), FromHex::from_hex("6000").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: Some((x!(135), vec![])) + }), + subs: vec![Trace { + depth: 1, + action: TraceAction::Call(TraceCall { + from: x!(0xa), + to: x!(0xb), + value: x!(0), + gas: x!(78934), + input: vec![], + result: Some((x!(69), vec![])) + }), + subs: vec![Trace { + depth: 2, + action: TraceAction::Call(TraceCall { + from: x!(0xb), + to: x!(0xc), + value: x!(0), + gas: x!(78868), + input: vec![], + result: Some((x!(3), vec![])) + }), + subs: vec![] + }] + }] + }); + + assert_eq!(result.trace, expected_trace); +} + +#[test] +fn should_trace_failed_subcall_with_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = x!(1_000_000); + let engine = TestEngine::new(5, Factory::default()); + + let t = Transaction { + nonce: x!(0), + gas_price: x!(0), + gas: x!(100_000), + action: Action::Call(x!(0xa)), + value: x!(100), + data: vec![],//600480600b6000396000f35b600056 + }.sign(&"".sha3()); + + state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&x!(0xb), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap()); + state.init_code(&x!(0xc), FromHex::from_hex("6000").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = Some(Trace { + depth: 0, + action: TraceAction::Call(TraceCall { + from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), + to: x!(0xa), + value: x!(100), + gas: x!(79000), + input: vec![], + result: Some((x!(79000), vec![])) + }), + subs: vec![Trace { + depth: 1, + action: TraceAction::Call(TraceCall { + from: x!(0xa), + to: x!(0xb), + value: x!(0), + gas: x!(78934), + input: vec![], + result: None + }), + subs: vec![Trace { + depth: 2, + action: TraceAction::Call(TraceCall { + from: x!(0xb), + to: x!(0xc), + value: x!(0), + gas: x!(78868), + input: vec![], + result: Some((x!(3), vec![])), + }), + subs: vec![] + }] + }] + }); + + assert_eq!(result.trace, expected_trace); +} #[test] fn code_from_database() { @@ -349,7 +1015,7 @@ fn code_from_database() { let temp = RandomTempPath::new(); let (root, db) = { let mut state = get_temp_state_in(temp.as_path()); - state.require_or_from(&a, false, ||Account::new_contract(U256::from(42u32)), |_|{}); + state.require_or_from(&a, false, ||Account::new_contract(x!(42), x!(0)), |_|{}); state.init_code(&a, vec![1, 2, 3]); assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec())); state.commit(); diff --git a/ethcore/src/substate.rs b/ethcore/src/substate.rs index 235ce2e97..9d81badb9 100644 --- a/ethcore/src/substate.rs +++ b/ethcore/src/substate.rs @@ -23,31 +23,53 @@ use common::*; pub struct Substate { /// Any accounts that have suicided. pub suicides: HashSet
, + /// Any logs. pub logs: Vec, + /// Refund counter of SSTORE nonzero -> zero. pub sstore_clears_count: U256, + /// Created contracts. - pub contracts_created: Vec
+ pub contracts_created: Vec
, + + /// The trace during this execution or `None` if we're not tracing. + pub subtraces: Option>, } impl Substate { /// Creates new substate. - pub fn new() -> Self { + pub fn new(tracing: bool) -> Self { Substate { - suicides: HashSet::new(), - logs: vec![], - sstore_clears_count: U256::zero(), - contracts_created: vec![] + suicides: Default::default(), + logs: Default::default(), + sstore_clears_count: Default::default(), + contracts_created: Default::default(), + subtraces: if tracing {Some(vec![])} else {None}, } } - /// Merge secondary substate `s` into self, accruing each element correspondingly. - pub fn accrue(&mut self, s: Substate) { + /// Merge tracing information from substate `s` if enabled. + pub fn accrue_trace(&mut self, subs: Option>, maybe_info: Option<(TraceAction, usize)>) { + // it failed, so we don't bother accrueing any protocol-level stuff, only the + // trace info. + if let Some(info) = maybe_info { + self.subtraces.as_mut().expect("maybe_action is Some: so we must be tracing: qed").push(Trace { + action: info.0, + depth: info.1, + subs: subs.expect("maybe_action is Some: so we must be tracing: qed"), + }); + } + } + + /// Merge secondary substate `s` into self, accruing each element correspondingly; will merge + /// tracing information too, if enabled. + pub fn accrue(&mut self, s: Substate, maybe_info: Option<(TraceAction, usize)>) { self.suicides.extend(s.suicides.into_iter()); self.logs.extend(s.logs.into_iter()); self.sstore_clears_count = self.sstore_clears_count + s.sstore_clears_count; self.contracts_created.extend(s.contracts_created.into_iter()); + self.accrue_trace(s.subtraces, maybe_info); } } @@ -58,24 +80,32 @@ mod tests { #[test] fn created() { - let sub_state = Substate::new(); + let sub_state = Substate::new(false); assert_eq!(sub_state.suicides.len(), 0); } #[test] fn accrue() { - let mut sub_state = Substate::new(); + let mut sub_state = Substate::new(false); sub_state.contracts_created.push(address_from_u64(1u64)); - sub_state.logs.push(LogEntry::new(address_from_u64(1u64), vec![], vec![])); + sub_state.logs.push(LogEntry { + address: address_from_u64(1u64), + topics: vec![], + data: vec![] + }); sub_state.sstore_clears_count = x!(5); sub_state.suicides.insert(address_from_u64(10u64)); - let mut sub_state_2 = Substate::new(); + let mut sub_state_2 = Substate::new(false); sub_state_2.contracts_created.push(address_from_u64(2u64)); - sub_state_2.logs.push(LogEntry::new(address_from_u64(1u64), vec![], vec![])); + sub_state_2.logs.push(LogEntry { + address: address_from_u64(1u64), + topics: vec![], + data: vec![] + }); sub_state_2.sstore_clears_count = x!(7); - sub_state.accrue(sub_state_2); + sub_state.accrue(sub_state_2, None); assert_eq!(sub_state.contracts_created.len(), 2); assert_eq!(sub_state.sstore_clears_count, x!(12)); assert_eq!(sub_state.suicides.len(), 1); diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index d025b4b78..64a2222b1 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -14,29 +14,42 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use client::{BlockChainClient, Client, BlockId}; +use client::{BlockChainClient, Client, ClientConfig, BlockId}; +use block::IsBlock; use tests::helpers::*; use common::*; +use devtools::*; #[test] fn created() { let dir = RandomTempPath::new(); - let client_result = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()); + let client_result = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()); assert!(client_result.is_ok()); } #[test] fn imports_from_empty() { let dir = RandomTempPath::new(); - let client = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); + let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); client.import_verified_blocks(&IoChannel::disconnected()); client.flush_queue(); } +#[test] +fn returns_state_root_basic() { + let client_result = generate_dummy_client(6); + let client = client_result.reference(); + let test_spec = get_test_spec(); + let test_engine = test_spec.to_engine().unwrap(); + let state_root = test_engine.spec().genesis_header().state_root; + + assert!(client.state_data(&state_root).is_some()); +} + #[test] fn imports_good_block() { let dir = RandomTempPath::new(); - let client = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); + let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); let good_block = get_good_dummy_block(); if let Err(_) = client.import_block(good_block) { panic!("error importing block being good by definition"); @@ -51,7 +64,7 @@ fn imports_good_block() { #[test] fn query_none_block() { let dir = RandomTempPath::new(); - let client = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); + let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); let non_existant = client.block_header(BlockId::Number(188)); assert!(non_existant.is_none()); @@ -103,5 +116,36 @@ fn can_collect_garbage() { let client_result = generate_dummy_client(100); let client = client_result.reference(); client.tick(); - assert!(client.cache_info().blocks < 100 * 1024); + assert!(client.blockchain_cache_info().blocks < 100 * 1024); +} + +#[test] +fn can_handle_long_fork() { + let client_result = generate_dummy_client(1200); + let client = client_result.reference(); + for _ in 0..10 { + client.import_verified_blocks(&IoChannel::disconnected()); + } + assert_eq!(1200, client.chain_info().best_block_number); + + push_blocks_to_client(client, 45, 1201, 800); + push_blocks_to_client(client, 49, 1201, 800); + push_blocks_to_client(client, 53, 1201, 600); + + for _ in 0..20 { + client.import_verified_blocks(&IoChannel::disconnected()); + } + assert_eq!(2000, client.chain_info().best_block_number); +} + +#[test] +fn can_mine() { + let dummy_blocks = get_good_dummy_block_seq(2); + 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().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/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 93e3e0a0d..dc3068560 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -14,18 +14,15 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use client::{BlockChainClient, Client}; -use std::env; +use client::{BlockChainClient, Client, ClientConfig}; use common::*; -use std::path::PathBuf; use spec::*; -use std::fs::{remove_dir_all}; -use blockchain::{BlockChain}; +use blockchain::{BlockChain, BlockChainConfig}; use state::*; -use rocksdb::*; use evm::{Schedule, Factory}; use engine::*; use ethereum; +use devtools::*; #[cfg(feature = "json-tests")] pub enum ChainEra { @@ -33,36 +30,6 @@ pub enum ChainEra { Homestead, } -pub struct RandomTempPath { - path: PathBuf -} - -impl RandomTempPath { - pub fn new() -> RandomTempPath { - let mut dir = env::temp_dir(); - dir.push(H32::random().hex()); - RandomTempPath { - path: dir.clone() - } - } - - pub fn as_path(&self) -> &PathBuf { - &self.path - } - - pub fn as_str(&self) -> &str { - self.path.to_str().unwrap() - } -} - -impl Drop for RandomTempPath { - fn drop(&mut self) { - if let Err(e) = remove_dir_all(self.as_path()) { - panic!("failed to remove temp directory, probably something failed to destroyed ({})", e); - } - } -} - #[cfg(test)] pub struct GuardedTempResult { result: Option, @@ -167,7 +134,7 @@ pub fn create_test_block_with_data(header: &Header, transactions: &[&SignedTrans pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult> { let dir = RandomTempPath::new(); - let client = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); + let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); let test_spec = get_test_spec(); let test_engine = test_spec.to_engine().unwrap(); let state_root = test_engine.spec().genesis_header().state_root; @@ -189,10 +156,9 @@ pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult rolling_block_number = rolling_block_number + 1; rolling_timestamp = rolling_timestamp + 10; - if let Err(_) = client.import_block(create_test_block(&header)) { - panic!("error importing block which is valid by definition"); + if let Err(e) = client.import_block(create_test_block(&header)) { + panic!("error importing block which is valid by definition: {:?}", e); } - } client.flush_queue(); client.import_verified_blocks(&IoChannel::disconnected()); @@ -203,9 +169,37 @@ pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult } } +pub fn push_blocks_to_client(client: &Arc, timestamp_salt: u64, starting_number: usize, block_number: usize) { + let test_spec = get_test_spec(); + let test_engine = test_spec.to_engine().unwrap(); + let state_root = test_engine.spec().genesis_header().state_root; + let mut rolling_hash = client.chain_info().best_block_hash; + let mut rolling_block_number = starting_number as u64; + let mut rolling_timestamp = timestamp_salt + starting_number as u64 * 10; + + for _ in 0..block_number { + let mut header = Header::new(); + + header.gas_limit = decode(test_engine.spec().engine_params.get("minGasLimit").unwrap()); + header.difficulty = decode(test_engine.spec().engine_params.get("minimumDifficulty").unwrap()); + header.timestamp = rolling_timestamp; + header.number = rolling_block_number; + header.parent_hash = rolling_hash; + header.state_root = state_root.clone(); + + rolling_hash = header.hash(); + rolling_block_number = rolling_block_number + 1; + rolling_timestamp = rolling_timestamp + 10; + + if let Err(e) = client.import_block(create_test_block(&header)) { + panic!("error importing block which is valid by definition: {:?}", e); + } + } +} + pub fn get_test_client_with_blocks(blocks: Vec) -> GuardedTempResult> { let dir = RandomTempPath::new(); - let client = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); + let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); for block in &blocks { if let Err(_) = client.import_block(block.clone()) { panic!("panic importing block which is well-formed"); @@ -222,9 +216,9 @@ pub fn get_test_client_with_blocks(blocks: Vec) -> GuardedTempResult GuardedTempResult { let temp = RandomTempPath::new(); - let bc = BlockChain::new(&create_unverifiable_block(0, H256::zero()), temp.as_path()); + let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), temp.as_path()); for block_order in 1..block_number { - bc.insert_block(&create_unverifiable_block(block_order, bc.best_block_hash())); + bc.insert_block(&create_unverifiable_block(block_order, bc.best_block_hash()), vec![]); } GuardedTempResult:: { @@ -235,9 +229,9 @@ pub fn generate_dummy_blockchain(block_number: u32) -> GuardedTempResult GuardedTempResult { let temp = RandomTempPath::new(); - let bc = BlockChain::new(&create_unverifiable_block(0, H256::zero()), temp.as_path()); + let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), temp.as_path()); for block_order in 1..block_number { - bc.insert_block(&create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None)); + bc.insert_block(&create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None), vec![]); } GuardedTempResult:: { @@ -248,7 +242,7 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> GuardedTempRes pub fn generate_dummy_empty_blockchain() -> GuardedTempResult { let temp = RandomTempPath::new(); - let bc = BlockChain::new(&create_unverifiable_block(0, H256::zero()), temp.as_path()); + let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), temp.as_path()); GuardedTempResult:: { _temp: temp, @@ -256,10 +250,9 @@ pub fn generate_dummy_empty_blockchain() -> GuardedTempResult { } } -pub fn get_temp_journal_db() -> GuardedTempResult { +pub fn get_temp_journal_db() -> GuardedTempResult> { let temp = RandomTempPath::new(); - let db = DB::open_default(temp.as_str()).unwrap(); - let journal_db = JournalDB::new(db); + let journal_db = journaldb::new(temp.as_str(), journaldb::Algorithm::EarlyMerge); GuardedTempResult { _temp: temp, result: Some(journal_db) @@ -275,9 +268,8 @@ pub fn get_temp_state() -> GuardedTempResult { } } -pub fn get_temp_journal_db_in(path: &Path) -> JournalDB { - let db = DB::open_default(path.to_str().unwrap()).unwrap(); - JournalDB::new(db) +pub fn get_temp_journal_db_in(path: &Path) -> Box { + journaldb::new(path.to_str().unwrap(), journaldb::Algorithm::EarlyMerge) } pub fn get_temp_state_in(path: &Path) -> State { @@ -285,6 +277,36 @@ pub fn get_temp_state_in(path: &Path) -> State { State::new(journal_db, U256::from(0u8)) } +pub fn get_good_dummy_block_seq(count: usize) -> Vec { + let test_spec = get_test_spec(); + let test_engine = test_spec.to_engine().unwrap(); + get_good_dummy_block_fork_seq(1, count, &test_engine.spec().genesis_header().hash()) +} + +pub fn get_good_dummy_block_fork_seq(start_number: usize, count: usize, parent_hash: &H256) -> Vec { + let test_spec = get_test_spec(); + let test_engine = test_spec.to_engine().unwrap(); + let mut rolling_timestamp = start_number as u64 * 10; + let mut parent = *parent_hash; + let mut r = Vec::new(); + for i in start_number .. start_number + count + 1 { + let mut block_header = Header::new(); + block_header.gas_limit = decode(test_engine.spec().engine_params.get("minGasLimit").unwrap()); + block_header.difficulty = U256::from(i).mul(U256([0, 1, 0, 0])); + block_header.timestamp = rolling_timestamp; + block_header.number = i as u64; + block_header.parent_hash = parent; + block_header.state_root = test_engine.spec().genesis_header().state_root; + + parent = block_header.hash(); + rolling_timestamp = rolling_timestamp + 10; + + r.push(create_test_block(&block_header)); + + } + r +} + pub fn get_good_dummy_block() -> Bytes { let mut block_header = Header::new(); let test_spec = get_test_spec(); diff --git a/ethcore/src/trace.rs b/ethcore/src/trace.rs new file mode 100644 index 000000000..858230bcd --- /dev/null +++ b/ethcore/src/trace.rs @@ -0,0 +1,111 @@ +// 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 . + +//! Tracing datatypes. +use common::*; + +/// Description of a _call_ action, either a `CALL` operation or a message transction. +#[derive(Debug, Clone, PartialEq)] +pub struct TraceCall { + /// The sending account. + pub from: Address, + /// The destination account. + pub to: Address, + /// The value transferred to the destination account. + pub value: U256, + /// The gas available for executing the call. + pub gas: U256, + /// The input data provided to the call. + pub input: Bytes, + /// The result of the operation; the gas used and the output data of the call. + pub result: Option<(U256, Bytes)>, +} + +/// Description of a _create_ action, either a `CREATE` operation or a create transction. +#[derive(Debug, Clone, PartialEq)] +pub struct TraceCreate { + /// The address of the creator. + pub from: Address, + /// The value with which the new account is endowed. + pub value: U256, + /// The gas available for the creation init code. + pub gas: U256, + /// The init code. + pub init: Bytes, + /// The result of the operation; tuple of the gas used, the address of the newly created account and its code. + /// NOTE: Presently failed operations are not reported so this will always be `Some`. + pub result: Option<(U256, Address, Bytes)>, +// pub output: Bytes, +} + +/// Description of an action that we trace; will be either a call or a create. +#[derive(Debug, Clone, PartialEq)] +pub enum TraceAction { + /// Action isn't yet known. + Unknown, + /// It's a call action. + Call(TraceCall), + /// It's a create action. + Create(TraceCreate), +} + +#[derive(Debug, Clone, PartialEq)] +/// A trace; includes a description of the action being traced and sub traces of each interior action. +pub struct Trace { + /// The number of EVM execution environments active when this action happened; 0 if it's + /// the outer action of the transaction. + pub depth: usize, + /// The action being performed. + pub action: TraceAction, + /// The sub traces for each interior action performed as part of this call. + pub subs: Vec, +} + +impl Default for Trace { + fn default() -> Trace { + Trace { + depth: 0, + action: TraceAction::Unknown, + subs: vec![], + } + } +} + +impl TraceAction { + /// Compose a `TraceAction` from an `ActionParams`, knowing that the action is a call. + pub fn from_call(p: &ActionParams) -> TraceAction { + TraceAction::Call(TraceCall { + from: p.sender.clone(), + to: p.address.clone(), + value: match p.value { ActionValue::Transfer(ref x) | ActionValue::Apparent(ref x) => x.clone() }, + gas: p.gas.clone(), + input: p.data.clone().unwrap_or(vec![]), + result: None, + }) + } + + /// Compose a `TraceAction` from an `ActionParams`, knowing that the action is a create. + pub fn from_create(p: &ActionParams) -> TraceAction { + TraceAction::Create(TraceCreate { + from: p.sender.clone(), + value: match p.value { ActionValue::Transfer(ref x) | ActionValue::Apparent(ref x) => x.clone() }, + gas: p.gas.clone(), + init: p.code.clone().unwrap_or(vec![]), + result: None, + }) + } +} + diff --git a/ethcore/src/transaction.rs b/ethcore/src/transaction.rs index b43c271d3..a51824494 100644 --- a/ethcore/src/transaction.rs +++ b/ethcore/src/transaction.rs @@ -37,10 +37,11 @@ impl Default for Action { impl Decodable for Action { fn decode(decoder: &D) -> Result where D: Decoder { let rlp = decoder.as_rlp(); - match rlp.is_empty() { - true => Ok(Action::Create), - false => Ok(Action::Call(try!(rlp.as_val()))) - } + if rlp.is_empty() { + Ok(Action::Create) + } else { + Ok(Action::Call(try!(rlp.as_val()))) + } } } @@ -79,6 +80,7 @@ impl Transaction { } impl FromJson for SignedTransaction { + #[cfg_attr(feature="dev", allow(single_char_pattern))] fn from_json(json: &Json) -> SignedTransaction { let t = Transaction { nonce: xjson!(&json["nonce"]), @@ -98,10 +100,10 @@ impl FromJson for SignedTransaction { v: match json.find("v") { Some(ref j) => u16::from_json(j) as u8, None => 0 }, r: match json.find("r") { Some(j) => xjson!(j), None => x!(0) }, s: match json.find("s") { Some(j) => xjson!(j), None => x!(0) }, - hash: RefCell::new(None), + hash: Cell::new(None), sender: match json.find("sender") { - Some(&Json::String(ref sender)) => RefCell::new(Some(address_from_hex(clean(sender)))), - _ => RefCell::new(None), + Some(&Json::String(ref sender)) => Cell::new(Some(address_from_hex(clean(sender)))), + _ => Cell::new(None), } } } @@ -110,7 +112,7 @@ impl FromJson for SignedTransaction { impl Transaction { /// The message hash of the transaction. - pub fn hash(&self) -> H256 { + pub fn hash(&self) -> H256 { let mut stream = RlpStream::new(); self.rlp_append_unsigned_transaction(&mut stream); stream.out().sha3() @@ -125,8 +127,8 @@ impl Transaction { r: r, s: s, v: v + 27, - hash: RefCell::new(None), - sender: RefCell::new(None) + hash: Cell::new(None), + sender: Cell::new(None), } } @@ -138,8 +140,8 @@ impl Transaction { r: U256::zero(), s: U256::zero(), v: 0, - hash: RefCell::new(None), - sender: RefCell::new(None) + hash: Cell::new(None), + sender: Cell::new(None), } } @@ -169,9 +171,9 @@ pub struct SignedTransaction { /// The S field of the signature; helps describe the point on the curve. s: U256, /// Cached hash. - hash: RefCell>, + hash: Cell>, /// Cached sender. - sender: RefCell> + sender: Cell>, } impl PartialEq for SignedTransaction { @@ -206,8 +208,8 @@ impl Decodable for SignedTransaction { v: try!(d.val_at(6)), r: try!(d.val_at(7)), s: try!(d.val_at(8)), - hash: RefCell::new(None), - sender: RefCell::new(None), + hash: Cell::new(None), + sender: Cell::new(None), }) } } @@ -236,13 +238,14 @@ impl SignedTransaction { /// Get the hash of this header (sha3 of the RLP). pub fn hash(&self) -> H256 { - let mut hash = self.hash.borrow_mut(); - match &mut *hash { - &mut Some(ref h) => h.clone(), - hash @ &mut None => { - *hash = Some(self.rlp_sha3()); - hash.as_ref().unwrap().clone() - } + let hash = self.hash.get(); + match hash { + Some(h) => h, + None => { + let h = self.rlp_sha3(); + self.hash.set(Some(h)); + h + } } } @@ -263,13 +266,14 @@ impl SignedTransaction { /// Returns transaction sender. pub fn sender(&self) -> Result { - let mut sender = self.sender.borrow_mut(); - match &mut *sender { - &mut Some(ref h) => Ok(h.clone()), - sender @ &mut None => { - *sender = Some(From::from(try!(ec::recover(&self.signature(), &self.unsigned.hash())).sha3())); - Ok(sender.as_ref().unwrap().clone()) - } + let sender = self.sender.get(); + match sender { + Some(s) => Ok(s), + None => { + let s = Address::from(try!(ec::recover(&self.signature(), &self.unsigned.hash())).sha3()); + self.sender.set(Some(s)); + Ok(s) + } } } diff --git a/ethcore/src/verification/canon_verifier.rs b/ethcore/src/verification/canon_verifier.rs new file mode 100644 index 000000000..30e368f1b --- /dev/null +++ b/ethcore/src/verification/canon_verifier.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 . + +use blockchain::BlockProvider; +use engine::Engine; +use error::Error; +use header::Header; +use super::Verifier; +use super::verification; + +pub struct CanonVerifier; + +impl Verifier for CanonVerifier { + fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &BlockProvider) -> Result<(), Error> { + verification::verify_block_family(header, bytes, engine, bc) + } + + fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error> { + verification::verify_block_final(expected, got) + } +} diff --git a/ethcore/src/verification/mod.rs b/ethcore/src/verification/mod.rs new file mode 100644 index 000000000..fe1f406cc --- /dev/null +++ b/ethcore/src/verification/mod.rs @@ -0,0 +1,27 @@ +// 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 . + +pub mod verification; +pub mod verifier; +mod canon_verifier; +#[cfg(test)] +mod noop_verifier; + +pub use self::verification::*; +pub use self::verifier::Verifier; +pub use self::canon_verifier::CanonVerifier; +#[cfg(test)] +pub use self::noop_verifier::NoopVerifier; diff --git a/ethcore/src/verification/noop_verifier.rs b/ethcore/src/verification/noop_verifier.rs new file mode 100644 index 000000000..20c15c3f1 --- /dev/null +++ b/ethcore/src/verification/noop_verifier.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 . + +use blockchain::BlockProvider; +use engine::Engine; +use error::Error; +use header::Header; +use super::Verifier; + +#[allow(dead_code)] +pub struct NoopVerifier; + +impl Verifier for NoopVerifier { + fn verify_block_family(_header: &Header, _bytes: &[u8], _engine: &Engine, _bc: &BlockProvider) -> Result<(), Error> { + Ok(()) + } + + fn verify_block_final(_expected: &Header, _got: &Header) -> Result<(), Error> { + Ok(()) + } +} diff --git a/ethcore/src/verification.rs b/ethcore/src/verification/verification.rs similarity index 95% rename from ethcore/src/verification.rs rename to ethcore/src/verification/verification.rs index c7d5e265f..6e79d737e 100644 --- a/ethcore/src/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -26,7 +26,7 @@ use engine::Engine; use blockchain::*; /// Preprocessed block data gathered in `verify_block_unordered` call -pub struct PreVerifiedBlock { +pub struct PreverifiedBlock { /// Populated block header pub header: Header, /// Populated block transactions @@ -55,13 +55,13 @@ pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &Engine) -> Res /// Phase 2 verification. Perform costly checks such as transaction signatures and block nonce for ethash. /// Still operates on a individual block -/// Returns a PreVerifiedBlock structure populated with transactions -pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> Result { +/// Returns a PreverifiedBlock structure populated with transactions +pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> Result { try!(engine.verify_block_unordered(&header, Some(&bytes))); for u in Rlp::new(&bytes).at(2).iter().map(|rlp| rlp.as_val::
()) { try!(engine.verify_block_unordered(&u, None)); } - // Verify transactions. + // Verify transactions. let mut transactions = Vec::new(); { let v = BlockView::new(&bytes); @@ -70,7 +70,7 @@ pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> transactions.push(t); } } - Ok(PreVerifiedBlock { + Ok(PreverifiedBlock { header: header, transactions: transactions, bytes: bytes, @@ -78,7 +78,7 @@ pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> } /// Phase 3 verification. Check block information against parent and uncles. -pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &BC) -> Result<(), Error> where BC: BlockProvider { +pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &BlockProvider) -> Result<(), Error> { // TODO: verify timestamp let parent = try!(bc.block_header(&header.parent_hash).ok_or_else(|| Error::from(BlockError::UnknownParent(header.parent_hash.clone())))); try!(verify_parent(&header, &parent)); @@ -94,7 +94,7 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, b excluded.insert(header.hash()); let mut hash = header.parent_hash.clone(); excluded.insert(hash.clone()); - for _ in 0..6 { + for _ in 0..engine.maximum_uncle_age() { match bc.block_details(&hash) { Some(details) => { excluded.insert(details.parent.clone()); @@ -121,7 +121,7 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, b // (8 Invalid) let depth = if header.number > uncle.number { header.number - uncle.number } else { 0 }; - if depth > 6 { + if depth > engine.maximum_uncle_age() as u64 { return Err(From::from(BlockError::UncleTooOld(OutOfBounds { min: Some(header.number - depth), max: Some(header.number - 1), found: uncle.number }))); } else if depth < 1 { @@ -141,7 +141,7 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, b let uncle_parent = try!(bc.block_header(&uncle.parent_hash).ok_or_else(|| Error::from(BlockError::UnknownUncleParent(uncle.parent_hash.clone())))); for _ in 0..depth { match bc.block_details(&expected_uncle_parent) { - Some(details) => { + Some(details) => { expected_uncle_parent = details.parent; }, None => break @@ -255,8 +255,14 @@ mod tests { numbers: HashMap, } + impl Default for TestBlockChain { + fn default() -> Self { + TestBlockChain::new() + } + } + impl TestBlockChain { - pub fn new() -> TestBlockChain { + pub fn new() -> Self { TestBlockChain { blocks: HashMap::new(), numbers: HashMap::new(), @@ -272,6 +278,8 @@ mod tests { } impl BlockProvider for TestBlockChain { + fn have_tracing(&self) -> bool { false } + fn is_known(&self, hash: &H256) -> bool { self.blocks.contains_key(hash) } @@ -302,6 +310,14 @@ mod tests { fn block_hash(&self, index: BlockNumber) -> Option { self.numbers.get(&index).cloned() } + + fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockNumber, _to_block: BlockNumber) -> Vec { + unimplemented!() + } + + fn block_receipts(&self, _hash: &H256) -> Option { + unimplemented!() + } } fn basic_test(bytes: &[u8], engine: &Engine) -> Result<(), Error> { @@ -460,7 +476,7 @@ mod tests { header.number = 9; check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref(), &bc), InvalidNumber(Mismatch { expected: parent.number + 1, found: header.number })); - + header = good.clone(); let mut bad_uncles = good_uncles.clone(); bad_uncles.push(good_uncle1.clone()); diff --git a/ethcore/src/verification/verifier.rs b/ethcore/src/verification/verifier.rs new file mode 100644 index 000000000..cc5edce29 --- /dev/null +++ b/ethcore/src/verification/verifier.rs @@ -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 . + +use blockchain::BlockProvider; +use engine::Engine; +use error::Error; +use header::Header; + +/// Should be used to verify blocks. +pub trait Verifier: Send + Sync { + fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: &BlockProvider) -> Result<(), Error>; + fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error>; +} diff --git a/ethcore/src/views.rs b/ethcore/src/views.rs index 4a7ff054d..11e26eb5f 100644 --- a/ethcore/src/views.rs +++ b/ethcore/src/views.rs @@ -223,6 +223,11 @@ impl<'a> BlockView<'a> { pub fn uncle_hashes(&self) -> Vec { self.rlp.at(2).iter().map(|rlp| rlp.as_raw().sha3()).collect() } + + /// Return nth uncle. + pub fn uncle_at(&self, index: usize) -> Option
{ + self.rlp.at(2).iter().nth(index).map(|rlp| rlp.as_val()) + } } impl<'a> Hashable for BlockView<'a> { @@ -251,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 } @@ -280,7 +288,7 @@ impl<'a> HeaderView<'a> { /// Returns block number. pub fn number(&self) -> BlockNumber { self.rlp.val_at(8) } - + /// Returns block gas limit. pub fn gas_limit(&self) -> U256 { self.rlp.val_at(9) } diff --git a/evmjit/Cargo.toml b/evmjit/Cargo.toml index ccd9cc718..6586a360e 100644 --- a/evmjit/Cargo.toml +++ b/evmjit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "evmjit" -version = "0.9.0" +version = "1.1.0" authors = ["debris "] [lib] diff --git a/hook.sh b/hook.sh index bb17f4e4f..58bff20ab 100755 --- a/hook.sh +++ b/hook.sh @@ -1,3 +1,12 @@ #!/bin/sh -echo "#!/bin/sh\ncargo test -p ethcore" >> ./.git/hooks/pre-push -chmod +x ./.git/hooks/pre-push +FILE=./.git/hooks/pre-push +echo "#!/bin/sh\n" > $FILE +# Exit on any error +echo "set -e" >> $FILE +# Run release build +echo "cargo build --release --features dev" >> $FILE +# Build tests +echo "cargo test --no-run --features dev \\" >> $FILE +echo " -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" >> $FILE +echo "" >> $FILE +chmod +x $FILE diff --git a/install-deps.sh b/install-deps.sh index 774d18720..7a5db1003 100755 --- a/install-deps.sh +++ b/install-deps.sh @@ -342,12 +342,9 @@ function run_installer() exe brew update echo - info "Installing rocksdb" - exe brew install rocksdb info "Installing multirust" exe brew install multirust - sudo multirust update nightly - sudo multirust default nightly + sudo multirust default beta echo } @@ -392,7 +389,6 @@ function run_installer() linux_version find_multirust - find_rocksdb find_curl find_git @@ -403,21 +399,6 @@ function run_installer() find_sudo } - function find_rocksdb() - { - depCount=$((depCount+1)) - if [[ $(ldconfig -v 2>/dev/null | grep rocksdb | wc -l) == 1 ]]; then - depFound=$((depFound+1)) - check "apt-get" - isRocksDB=true - INSTALL_FILES+="${blue}${dim}==> librocksdb:${reset}$n" - else - uncheck "librocksdb is missing" - isRocksDB=false - INSTALL_FILES+="${blue}${dim}==> librocksdb:${reset}$n" - fi - } - function find_multirust() { depCount=$((depCount+2)) @@ -426,20 +407,20 @@ function run_installer() depFound=$((depFound+1)) check "multirust" isMultirust=true - if [[ $(multirust show-default 2>/dev/null | grep nightly | wc -l) == 4 ]]; then + if [[ $(multirust show-default 2>/dev/null | grep beta | wc -l) == 3 ]]; then depFound=$((depFound+1)) - check "rust nightly" - isMultirustNightly=true + check "rust beta" + isMultirustBeta=true else - uncheck "rust is not nightly" - isMultirustNightly=false - INSTALL_FILES+="${blue}${dim}==> multirust -> rust nightly:${reset}${n}" + uncheck "rust is not beta" + isMultirustBeta=false + INSTALL_FILES+="${blue}${dim}==> multirust -> rust beta:${reset}${n}" fi else uncheck "multirust is missing" - uncheck "rust nightly is missing" + uncheck "rust beta is missing" isMultirust=false - isMultirustNightly=false + isMultirustBeta=false INSTALL_FILES+="${blue}${dim}==> multirust:${reset}${n}" fi } @@ -563,34 +544,6 @@ function run_installer() fi } - function ubuntu_rocksdb_installer() - { - sudo apt-get update -qq - sudo apt-get install -qq -y software-properties-common - sudo apt-add-repository -y ppa:ethcore/ethcore - sudo apt-get -f -y install - sudo apt-get update -qq - sudo apt-get install -qq -y librocksdb-dev librocksdb - } - - function linux_rocksdb_installer() - { - if [[ $isUbuntu == true ]]; then - ubuntu_rocksdb_installer - else - oldpwd=`pwd` - cd /tmp - exe git clone --branch v4.2 --depth=1 https://github.com/facebook/rocksdb.git - cd rocksdb - exe make shared_lib - sudo cp -a librocksdb.so* /usr/lib - sudo ldconfig - cd /tmp - rm -rf /tmp/rocksdb - cd $oldpwd - fi - } - function linux_installer() { if [[ $isGCC == false || $isGit == false || $isMake == false || $isCurl == false ]]; then @@ -611,25 +564,18 @@ function run_installer() echo fi - if [[ $isRocksDB == false ]]; then - info "Installing rocksdb..." - linux_rocksdb_installer - echo - fi - if [[ $isMultirust == false ]]; then info "Installing multirust..." if [[ $isSudo == false ]]; then apt-get install -q -y sudo fi - curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sudo sh -s -- --yes + curl -sf https://raw.githubusercontent.com/brson/multirust/master/quick-install.sh | sudo sh -s -- --yes echo fi - if [[ $isMultirustNightly == false ]]; then - info "Installing rust nightly..." - multirust update nightly - multirust default nightly + if [[ $isMultirustBeta == false ]]; then + info "Installing rust beta..." + multirust default beta echo fi } @@ -657,10 +603,9 @@ function run_installer() find_git find_make find_gcc - find_rocksdb find_multirust - if [[ $isCurl == false || $isGit == false || $isMake == false || $isGCC == false || $isRocksDB == false || $isMultirustNightly == false ]]; then + if [[ $isCurl == false || $isGit == false || $isMake == false || $isGCC == false || $isMultirustBeta == false ]]; then abort_install fi fi diff --git a/install-parity.sh b/install-parity.sh index 60d3471d5..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() @@ -236,14 +236,29 @@ function run_installer() { linux_version - find_rocksdb - find_curl find_apt find_sudo } + function find_git() + { + depCount=$((depCount+1)) + GIT_PATH=`which git 2>/dev/null` + + if [[ -f $GIT_PATH ]] + then + depFound=$((depFound+1)) + check "git" + isGit=true + else + uncheck "git is missing" + isGit=false + INSTALL_FILES+="${blue}${dim}==> git:${reset}${n}" + fi + } + function find_brew() { BREW_PATH=`which brew 2>/dev/null` @@ -333,20 +348,6 @@ function run_installer() fi } - function find_rocksdb() - { - depCount=$((depCount+1)) - if [[ $(ldconfig -v 2>/dev/null | grep rocksdb | wc -l) == 1 ]]; then - depFound=$((depFound+1)) - check "librocksdb" - isRocksDB=true - else - uncheck "librocksdb is missing" - isRocksDB=false - INSTALL_FILES+="${blue}${dim}==>${reset}\tlibrocksdb${n}" - fi - } - function find_apt() { depCount=$((depCount+1)) @@ -386,10 +387,9 @@ function run_installer() info "Verifying installation" if [[ $OS_TYPE == "linux" ]]; then - find_rocksdb find_apt - if [[ $isRocksDB == false || $isApt == false ]]; then + if [[ $isApt == false ]]; then abortInstall fi fi @@ -397,23 +397,11 @@ function run_installer() function linux_deps_installer() { - if [[ $isRocksDB == false || $isCurl == false ]]; then + if [[ $isCurl == false ]]; then info "Preparing apt..." sudo apt-get update -qq echo fi - - if [[ $isRocksDB == false ]]; then - info "Installing rocksdb..." - - sudo apt-get install -qq -y software-properties-common - sudo apt-add-repository -y ppa:ethcore/ethcore - sudo apt-get -f -y install - sudo apt-get update -qq - sudo apt-get install -qq -y librocksdb - - echo - fi if [[ $isCurl == false ]]; then info "Installing curl..." 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 new file mode 100644 index 000000000..2d5bf8e61 --- /dev/null +++ b/miner/Cargo.toml @@ -0,0 +1,24 @@ +[package] +description = "Ethminer library" +homepage = "http://ethcore.io" +license = "GPL-3.0" +name = "ethminer" +version = "1.1.0" +authors = ["Ethcore "] +build = "build.rs" + +[build-dependencies] +rustc_version = "0.1" + +[dependencies] +ethcore-util = { path = "../util" } +ethcore = { path = "../ethcore" } +log = "0.3" +env_logger = "0.3" +rustc-serialize = "0.3" +rayon = "0.3.1" +clippy = { version = "0.0.54", optional = true } + +[features] +default = [] +dev = ["clippy"] diff --git a/miner/build.rs b/miner/build.rs new file mode 100644 index 000000000..41b9a1b3e --- /dev/null +++ b/miner/build.rs @@ -0,0 +1,25 @@ +// 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_version; + +use rustc_version::{version_meta, Channel}; + +fn main() { + if let Channel::Nightly = version_meta().channel { + println!("cargo:rustc-cfg=nightly"); + } +} diff --git a/miner/src/lib.rs b/miner/src/lib.rs new file mode 100644 index 000000000..06faf057e --- /dev/null +++ b/miner/src/lib.rs @@ -0,0 +1,118 @@ +// 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 . + +#![warn(missing_docs)] +#![cfg_attr(all(nightly, feature="dev"), feature(plugin))] +#![cfg_attr(all(nightly, feature="dev"), plugin(clippy))] + +//! Miner module +//! Keeps track of transactions and mined block. +//! +//! Usage example: +//! +//! ```rust +//! extern crate ethcore_util as util; +//! extern crate ethcore; +//! extern crate ethminer; +//! use std::ops::Deref; +//! use std::env; +//! use std::sync::Arc; +//! use util::network::{NetworkService, NetworkConfiguration}; +//! use ethcore::client::{Client, ClientConfig, BlockChainClient}; +//! use ethcore::ethereum; +//! use ethminer::{Miner, MinerService}; +//! +//! fn main() { +//! let mut service = NetworkService::start(NetworkConfiguration::new()).unwrap(); +//! let dir = env::temp_dir(); +//! let client = Client::new(ClientConfig::default(), ethereum::new_frontier(), &dir, service.io().channel()).unwrap(); +//! +//! let miner: Miner = Miner::default(); +//! // get status +//! assert_eq!(miner.status().transactions_in_pending_queue, 0); +//! +//! // Check block for sealing +//! assert!(miner.sealing_block(client.deref()).lock().unwrap().is_some()); +//! } +//! ``` + + +#[macro_use] +extern crate log; +#[macro_use] +extern crate ethcore_util as util; +extern crate ethcore; +extern crate env_logger; +extern crate rayon; + +mod miner; +mod transaction_queue; + +pub use transaction_queue::{TransactionQueue, AccountDetails}; +pub use miner::{Miner}; + +use std::sync::Mutex; +use util::{H256, Address, FixedHash, Bytes}; +use ethcore::client::{BlockChainClient}; +use ethcore::block::{ClosedBlock}; +use ethcore::error::{Error}; +use ethcore::transaction::SignedTransaction; + +/// Miner client API +pub trait MinerService : Send + Sync { + + /// Returns miner's status. + fn status(&self) -> MinerStatus; + + /// Get the author that we will seal blocks as. + fn author(&self) -> Address { Address::zero() } + + /// Get the extra_data that we will seal blocks wuth. + fn extra_data(&self) -> Bytes { vec![] } + + /// Imports transactions to transaction queue. + 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; + + /// Removes all transactions from the queue and restart mining operation. + fn clear_and_reset(&self, chain: &BlockChainClient); + + /// Called when blocks are imported to chain, updates transactions queue. + fn chain_new_blocks(&self, chain: &BlockChainClient, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]); + + /// New chain head event. Restart mining operation. + 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>; + + /// 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>; +} + +/// Mining status +pub struct MinerStatus { + /// Number of transactions in queue with state `pending` (ready to be included in block) + pub transactions_in_pending_queue: usize, + /// Number of transactions in queue with state `future` (not yet ready to be included in block) + 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 new file mode 100644 index 000000000..d4f6c8a00 --- /dev/null +++ b/miner/src/miner.rs @@ -0,0 +1,313 @@ +// 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 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, HeaderView}; +use ethcore::client::{BlockChainClient, BlockId}; +use ethcore::block::{ClosedBlock, IsBlock}; +use ethcore::error::{Error}; +use ethcore::transaction::SignedTransaction; +use super::{MinerService, MinerStatus, TransactionQueue, AccountDetails}; + +/// Keeps track of transactions using priority queue and holds currently mined block. +pub struct Miner { + transaction_queue: Mutex, + + // for sealing... + sealing_enabled: AtomicBool, + sealing_block_last_request: Mutex, + sealing_block: Mutex>, + gas_floor_target: RwLock, + author: RwLock
, + extra_data: RwLock, + +} + +impl Default for Miner { + fn default() -> 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()), + extra_data: RwLock::new(Vec::new()), + } + } +} + +impl Miner { + /// Creates new instance of miner + pub fn new() -> Arc { + Arc::new(Miner::default()) + } + + /// Get the author that we will seal blocks as. + fn author(&self) -> Address { + *self.author.read().unwrap() + } + + /// Get the extra_data that we will seal blocks wuth. + fn extra_data(&self) -> Bytes { + self.extra_data.read().unwrap().clone() + } + + /// Get the extra_data that we will seal blocks wuth. + fn gas_floor_target(&self) -> U256 { + *self.gas_floor_target.read().unwrap() + } + + /// Set the author that we will seal blocks as. + pub fn set_author(&self, author: Address) { + *self.author.write().unwrap() = author; + } + + /// Set the extra_data that we will seal blocks with. + pub fn set_extra_data(&self, extra_data: Bytes) { + *self.extra_data.write().unwrap() = extra_data; + } + + /// Set the gas limit we wish to target when sealing a new block. + pub fn set_gas_floor_target(&self, target: U256) { + *self.gas_floor_target.write().unwrap() = target; + } + + /// Set minimal gas price of transaction to be accepted for mining. + 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.update_sealing(chain); + } + + fn status(&self) -> MinerStatus { + let status = self.transaction_queue.lock().unwrap().status(); + let block = self.sealing_block.lock().unwrap(); + MinerStatus { + 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 author(&self) -> Address { + *self.author.read().unwrap() + } + + fn extra_data(&self) -> Bytes { + self.extra_data.read().unwrap().clone() + } + + 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_account) + } + + fn pending_transactions_hashes(&self) -> Vec { + let transaction_queue = self.transaction_queue.lock().unwrap(); + transaction_queue.pending_hashes() + } + + 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 + }; + + 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); + + self.prepare_sealing(chain); + } + *self.sealing_block_last_request.lock().unwrap() = chain.chain_info().best_block_number; + &self.sealing_block + } + + fn submit_seal(&self, chain: &BlockChainClient, pow_hash: H256, seal: Vec) -> Result<(), Error> { + let mut maybe_b = self.sealing_block.lock().unwrap(); + match *maybe_b { + Some(ref b) if b.hash() == pow_hash => {} + _ => { return Err(Error::PowHashInvalid); } + } + + let b = maybe_b.take(); + match chain.try_seal(b.unwrap(), seal) { + Err(old) => { + *maybe_b = Some(old); + Err(Error::PowInvalid) + } + Ok(sealed) => { + // TODO: commit DB from `sealed.drain` and make a VerifiedBlock to skip running the transactions twice. + try!(chain.import_block(sealed.rlp_bytes())); + Ok(()) + } + } + } + + fn chain_new_blocks(&self, chain: &BlockChainClient, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]) { + fn fetch_transactions(chain: &BlockChainClient, hash: &H256) -> Vec { + let block = chain + .block(BlockId::Hash(*hash)) + // Client should send message after commit to db and inserting to chain. + .expect("Expected in-chain blocks."); + let block = BlockView::new(&block); + block.transactions() + } + + // First update gas limit in transaction queue + self.update_gas_limit(chain); + + // Then import all transactions... + { + let out_of_chain = retracted + .par_iter() + .map(|h| fetch_transactions(chain, h)); + 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| AccountDetails { + nonce: chain.nonce(a), + balance: chain.balance(a) + }); + }); + } + + // ...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 new file mode 100644 index 000000000..9abe80f1c --- /dev/null +++ b/miner/src/transaction_queue.rs @@ -0,0 +1,1247 @@ +// 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 . + +// TODO [todr] - own transactions should have higher priority + +//! Transaction Queue +//! +//! TransactionQueue keeps track of all transactions seen by the node (received from other peers) and own transactions +//! and orders them by priority. Top priority transactions are those with low nonce height (difference between +//! transaction's nonce and next nonce expected from this sender). If nonces are equal transaction's gas price is used +//! for comparison (higher gas price = higher priority). +//! +//! # Usage Example +//! +//! ```rust +//! extern crate ethcore_util as util; +//! extern crate ethcore; +//! extern crate ethminer; +//! extern crate rustc_serialize; +//! +//! use util::crypto::KeyPair; +//! use util::hash::Address; +//! use util::numbers::{Uint, U256}; +//! use ethminer::{TransactionQueue, AccountDetails}; +//! use ethcore::transaction::*; +//! use rustc_serialize::hex::FromHex; +//! +//! fn main() { +//! let key = KeyPair::create().unwrap(); +//! let t1 = Transaction { action: Action::Create, value: U256::from(100), data: "3331600055".from_hex().unwrap(), +//! gas: U256::from(100_000), gas_price: U256::one(), nonce: U256::from(10) }; +//! let t2 = Transaction { action: Action::Create, value: U256::from(100), data: "3331600055".from_hex().unwrap(), +//! gas: U256::from(100_000), gas_price: U256::one(), nonce: U256::from(11) }; +//! +//! let st1 = t1.sign(&key.secret()); +//! let st2 = t2.sign(&key.secret()); +//! 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).unwrap(); +//! txq.add(st1.clone(), &default_nonce).unwrap(); +//! +//! // Check status +//! assert_eq!(txq.status().pending, 2); +//! // Check top transactions +//! let top = txq.top_transactions(); +//! assert_eq!(top.len(), 2); +//! assert_eq!(top[0], st1); +//! assert_eq!(top[1], st2); +//! +//! // And when transaction is removed (but nonce haven't changed) +//! // it will move invalid transactions to future +//! txq.remove(&st1.hash(), &default_nonce); +//! assert_eq!(txq.status().pending, 0); +//! assert_eq!(txq.status().future, 1); +//! assert_eq!(txq.top_transactions().len(), 0); +//! } +//! ``` +//! +//! # Maintaing valid state +//! +//! 1. Whenever transaction is imported to queue (to queue) all other transactions from this sender are revalidated in current. It means that they are moved to future and back again (height recalculation & gap filling). +//! 2. Whenever transaction is removed: +//! - When it's removed from `future` - all `future` transactions heights are recalculated and then +//! we check if the transactions should go to `current` (comparing state nonce) +//! - When it's removed from `current` - all transactions from this sender (`current` & `future`) are recalculated. +//! + +use std::default::Default; +use std::cmp::{Ordering}; +use std::collections::{HashMap, BTreeSet}; +use util::numbers::{Uint, U256}; +use util::hash::{Address, H256}; +use util::table::*; +use ethcore::transaction::*; +use ethcore::error::{Error, TransactionError}; + + +#[derive(Clone, Debug)] +/// Light structure used to identify transaction and it's order +struct TransactionOrder { + /// Primary ordering factory. Difference between transaction nonce and expected nonce in state + /// (e.g. Tx(nonce:5), State(nonce:0) -> height: 5) + /// High nonce_height = Low priority (processed later) + nonce_height: U256, + /// Gas Price of the transaction. + /// Low gas price = Low priority (processed later) + gas_price: U256, + /// Hash to identify associated transaction + hash: H256, +} + + +impl TransactionOrder { + fn for_transaction(tx: &VerifiedTransaction, base_nonce: U256) -> Self { + TransactionOrder { + nonce_height: tx.nonce() - base_nonce, + gas_price: tx.transaction.gas_price, + hash: tx.hash(), + } + } + + fn update_height(mut self, nonce: U256, base_nonce: U256) -> Self { + self.nonce_height = nonce - base_nonce; + self + } +} + +impl Eq for TransactionOrder {} +impl PartialEq for TransactionOrder { + fn eq(&self, other: &TransactionOrder) -> bool { + self.cmp(other) == Ordering::Equal + } +} +impl PartialOrd for TransactionOrder { + fn partial_cmp(&self, other: &TransactionOrder) -> Option { + Some(self.cmp(other)) + } +} +impl Ord for TransactionOrder { + fn cmp(&self, b: &TransactionOrder) -> Ordering { + // First check nonce_height + if self.nonce_height != b.nonce_height { + return self.nonce_height.cmp(&b.nonce_height); + } + + // Then compare gas_prices + let a_gas = self.gas_price; + let b_gas = b.gas_price; + if a_gas != b_gas { + return b_gas.cmp(&a_gas); + } + + // Compare hashes + self.hash.cmp(&b.hash) + } +} + +/// Verified transaction (with sender) +struct VerifiedTransaction { + transaction: SignedTransaction +} +impl VerifiedTransaction { + fn new(transaction: SignedTransaction) -> Result { + try!(transaction.sender()); + Ok(VerifiedTransaction { + transaction: transaction + }) + } + + fn hash(&self) -> H256 { + self.transaction.hash() + } + + fn nonce(&self) -> U256 { + self.transaction.nonce + } + + fn sender(&self) -> Address { + self.transaction.sender().unwrap() + } +} + +/// Holds transactions accessible by (address, nonce) and by priority +/// +/// TransactionSet keeps number of entries below limit, but it doesn't +/// automatically happen during `insert/remove` operations. +/// You have to call `enforce_limit` to remove lowest priority transactions from set. +struct TransactionSet { + by_priority: BTreeSet, + by_address: Table, + limit: usize, +} + +impl TransactionSet { + /// Inserts `TransactionOrder` to this set + fn insert(&mut self, sender: Address, nonce: U256, order: TransactionOrder) -> Option { + self.by_priority.insert(order.clone()); + let r = self.by_address.insert(sender, nonce, order); + // If transaction was replaced remove it from priority queue + if let Some(ref order) = r { + self.by_priority.remove(order); + } + r + } + + /// Remove low priority transactions if there is more then specified by given `limit`. + /// + /// It drops transactions from this set but also removes associated `VerifiedTransaction`. + fn enforce_limit(&mut self, by_hash: &mut HashMap) { + let len = self.by_priority.len(); + if len <= self.limit { + return; + } + + let to_drop : Vec<(Address, U256)> = { + self.by_priority + .iter() + .skip(self.limit) + .map(|order| by_hash.get(&order.hash).expect("Inconsistency in queue detected.")) + .map(|tx| (tx.sender(), tx.nonce())) + .collect() + }; + + for (sender, nonce) in to_drop { + let order = self.drop(&sender, &nonce).expect("Dropping transaction found in priority queue failed."); + by_hash.remove(&order.hash).expect("Inconsistency in queue."); + } + } + + /// Drop transaction from this set (remove from `by_priority` and `by_address`) + fn drop(&mut self, sender: &Address, nonce: &U256) -> Option { + if let Some(tx_order) = self.by_address.remove(sender, nonce) { + self.by_priority.remove(&tx_order); + return Some(tx_order); + } + None + } + + /// Drop all transactions. + fn clear(&mut self) { + self.by_priority.clear(); + self.by_address.clear(); + } +} + +#[derive(Debug)] +/// Current status of the queue +pub struct TransactionQueueStatus { + /// Number of pending transactions (ready to go to block) + pub pending: usize, + /// Number of future transactions (waiting for transactions with lower nonces first) + 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 + future: TransactionSet, + /// All transactions managed by queue indexed by hash + by_hash: HashMap, + /// Last nonce of transaction in current (to quickly check next expected transaction) + last_nonces: HashMap, +} + +impl Default for TransactionQueue { + fn default() -> Self { + TransactionQueue::new() + } +} + +impl TransactionQueue { + /// Creates new instance of this Queue + pub fn new() -> Self { + Self::with_limits(1024, 1024) + } + + /// Create new instance of this Queue with specified limits + pub fn with_limits(current_limit: usize, future_limit: usize) -> Self { + let current = TransactionSet { + by_priority: BTreeSet::new(), + by_address: Table::new(), + limit: current_limit, + }; + let future = TransactionSet { + by_priority: BTreeSet::new(), + by_address: Table::new(), + limit: future_limit, + }; + + TransactionQueue { + minimal_gas_price: U256::zero(), + gas_limit: !U256::zero(), + current: current, + future: future, + by_hash: HashMap::new(), + last_nonces: HashMap::new(), + } + } + + /// Sets new gas price threshold for incoming transactions. + /// 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, + }; + } + + /// Returns current status for this queue + pub fn status(&self) -> TransactionQueueStatus { + TransactionQueueStatus { + pending: self.current.by_priority.len(), + future: self.future.by_priority.len(), + } + } + + /// Adds all signed transactions to queue to be verified and imported + 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_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: "miner", + "Dropping transaction below minimal gas price threshold: {:?} (gp: {} < {})", + tx.hash(), tx.gas_price, self.minimal_gas_price + ); + + return Err(Error::Transaction(TransactionError::InsufficientGasPrice { + minimal: self.minimal_gas_price, + got: tx.gas_price, + })); + } + + 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_account: T) + where T: Fn(&Address) -> AccountDetails { + for hash in transaction_hashes { + 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_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 + return; + } + + let transaction = transaction.unwrap(); + let sender = transaction.sender(); + let nonce = transaction.nonce(); + let current_nonce = fetch_account(&sender).nonce; + + + // Remove from future + let order = self.future.drop(&sender, &nonce); + if order.is_some() { + self.update_future(&sender, current_nonce); + // And now lets check if there is some chain of transactions in future + // that should be placed in current + self.move_matching_future_to_current(sender, current_nonce, current_nonce); + return; + } + + // Remove from current + let order = self.current.drop(&sender, &nonce); + if order.is_some() { + // We will either move transaction to future or remove it completely + // so there will be no transactions from this sender in current + self.last_nonces.remove(&sender); + // First update height of transactions in future to avoid collisions + self.update_future(&sender, current_nonce); + // This should move all current transactions to future and remove old transactions + self.move_all_to_future(&sender, current_nonce); + // And now lets check if there is some chain of transactions in future + // that should be placed in current. It should also update last_nonces. + self.move_matching_future_to_current(sender, current_nonce, current_nonce); + return; + } + } + + /// Update height of all transactions in future transactions set. + fn update_future(&mut self, sender: &Address, current_nonce: U256) { + // We need to drain all transactions for current sender from future and reinsert them with updated height + let all_nonces_from_sender = match self.future.by_address.row(&sender) { + Some(row_map) => row_map.keys().cloned().collect::>(), + None => vec![], + }; + for k in all_nonces_from_sender { + let order = self.future.drop(&sender, &k).unwrap(); + 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); + } + } + } + + /// Drop all transactions from given sender from `current`. + /// Either moves them to `future` or removes them from queue completely. + fn move_all_to_future(&mut self, sender: &Address, current_nonce: U256) { + let all_nonces_from_sender = match self.current.by_address.row(&sender) { + Some(row_map) => row_map.keys().cloned().collect::>(), + None => vec![], + }; + + for k in all_nonces_from_sender { + // Goes to future or is removed + let order = self.current.drop(&sender, &k).unwrap(); + 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); + } + + /// Returns top transactions from the queue ordered by priority. + pub fn top_transactions(&self) -> Vec { + self.current.by_priority + .iter() + .map(|t| self.by_hash.get(&t.hash).expect("Transaction Queue Inconsistency")) + .map(|t| t.transaction.clone()) + .collect() + } + + /// Returns hashes of all transactions from current, ordered by priority. + pub fn pending_hashes(&self) -> Vec { + self.current.by_priority + .iter() + .map(|t| t.hash) + .collect() + } + + /// Removes all elements (in any state) from the queue + pub fn clear(&mut self) { + self.current.clear(); + self.future.clear(); + self.by_hash.clear(); + self.last_nonces.clear(); + } + + /// Checks if there are any transactions in `future` that should actually be promoted to `current` + /// (because nonce matches). + fn move_matching_future_to_current(&mut self, address: Address, mut current_nonce: U256, first_nonce: U256) { + { + let by_nonce = self.future.by_address.row_mut(&address); + if let None = by_nonce { + return; + } + let mut by_nonce = by_nonce.unwrap(); + while let Some(order) = by_nonce.remove(¤t_nonce) { + // remove also from priority and hash + self.future.by_priority.remove(&order); + // Put to current + let order = order.update_height(current_nonce, first_nonce); + self.current.insert(address, current_nonce, order); + current_nonce = current_nonce + U256::one(); + } + } + self.future.by_address.clear_if_empty(&address); + // Update last inserted nonce + self.last_nonces.insert(address, current_nonce - U256::one()); + } + + /// Adds VerifiedTransaction to this queue. + /// + /// Determines if it should be placed in current or future. When transaction is + /// imported to `current` also checks if there are any `future` transactions that should be promoted because of + /// this. + /// + /// 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. + /// + /// 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: "miner", "Dropping already imported transaction: {:?}", tx.hash()); + return Err(TransactionError::AlreadyImported); + } + + + let address = tx.sender(); + let nonce = tx.nonce(); + + let next_nonce = self.last_nonces + .get(&address) + .cloned() + .map_or(state_nonce, |n| n + U256::one()); + + // Check height + if nonce > next_nonce { + // 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 Ok(()); + } else if nonce < state_nonce { + // Droping transaction + 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); + // Keep track of highest nonce stored in current + self.last_nonces.insert(address, nonce); + // Update nonces of transactions in future + self.update_future(&address, state_nonce); + // Maybe there are some more items waiting in future? + self.move_matching_future_to_current(address, nonce + U256::one(), state_nonce); + // There might be exactly the same transaction waiting in future + // same (sender, nonce), but above function would not move it. + if let Some(order) = self.future.drop(&address, &nonce) { + // Let's insert that transaction to current (if it has higher gas_price) + let future_tx = self.by_hash.remove(&order.hash).unwrap(); + Self::replace_transaction(future_tx, state_nonce, &mut self.current, &mut self.by_hash); + } + // Also enforce the limit + 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`). + /// + /// If there is already transaction with same `(sender, nonce)` it will be replaced iff `gas_price` is higher. + /// One of the transactions is dropped from set and also removed from queue entirely (from `by_hash`). + fn replace_transaction(tx: VerifiedTransaction, base_nonce: U256, set: &mut TransactionSet, by_hash: &mut HashMap) { + let order = TransactionOrder::for_transaction(&tx, base_nonce); + let hash = tx.hash(); + let address = tx.sender(); + let nonce = tx.nonce(); + + by_hash.insert(hash, tx); + if let Some(old) = set.insert(address, nonce, order.clone()) { + // There was already transaction in queue. Let's check which one should stay + let old_fee = old.gas_price; + let new_fee = order.gas_price; + if old_fee.cmp(&new_fee) == Ordering::Greater { + // Put back old transaction since it has greater priority (higher gas_price) + set.insert(address, nonce, old); + // and remove new one + by_hash.remove(&hash); + } else { + // Make sure we remove old transaction entirely + by_hash.remove(&old.hash); + } + } + } +} + + +#[cfg(test)] +mod test { + extern crate rustc_serialize; + use util::table::*; + use util::*; + use ethcore::transaction::*; + use super::*; + use super::{TransactionSet, TransactionOrder, VerifiedTransaction}; + + fn new_unsigned_tx(nonce: U256) -> Transaction { + Transaction { + action: Action::Create, + value: U256::from(100), + data: "3331600055".from_hex().unwrap(), + gas: U256::from(100_000), + gas_price: U256::one(), + nonce: nonce + } + } + + fn new_tx() -> SignedTransaction { + let keypair = KeyPair::create().unwrap(); + new_unsigned_tx(U256::from(123)).sign(&keypair.secret()) + } + + fn default_nonce(_address: &Address) -> AccountDetails { + AccountDetails { + nonce: U256::from(123), + balance: !U256::zero() + } + } + + /// Returns two transactions with identical (sender, nonce) but different hashes + fn new_similar_txs() -> (SignedTransaction, SignedTransaction) { + let keypair = KeyPair::create().unwrap(); + let secret = &keypair.secret(); + let nonce = U256::from(123); + let tx = new_unsigned_tx(nonce); + let mut tx2 = new_unsigned_tx(nonce); + tx2.gas_price = U256::from(2); + + (tx.sign(secret), tx2.sign(secret)) + } + + fn new_txs(second_nonce: U256) -> (SignedTransaction, SignedTransaction) { + let keypair = KeyPair::create().unwrap(); + let secret = &keypair.secret(); + let nonce = U256::from(123); + let tx = new_unsigned_tx(nonce); + let tx2 = new_unsigned_tx(nonce + second_nonce); + + (tx.sign(secret), tx2.sign(secret)) + } + + #[test] + fn should_create_transaction_set() { + // given + let mut set = TransactionSet { + by_priority: BTreeSet::new(), + by_address: Table::new(), + limit: 1 + }; + let (tx1, tx2) = new_txs(U256::from(1)); + let tx1 = VerifiedTransaction::new(tx1).unwrap(); + let tx2 = VerifiedTransaction::new(tx2).unwrap(); + let mut by_hash = { + let mut x = HashMap::new(); + let tx1 = VerifiedTransaction::new(tx1.transaction.clone()).unwrap(); + let tx2 = VerifiedTransaction::new(tx2.transaction.clone()).unwrap(); + x.insert(tx1.hash(), tx1); + x.insert(tx2.hash(), tx2); + x + }; + // Insert both transactions + let order1 = TransactionOrder::for_transaction(&tx1, U256::zero()); + set.insert(tx1.sender(), tx1.nonce(), order1.clone()); + let order2 = TransactionOrder::for_transaction(&tx2, U256::zero()); + set.insert(tx2.sender(), tx2.nonce(), order2.clone()); + assert_eq!(set.by_priority.len(), 2); + assert_eq!(set.by_address.len(), 2); + + // when + set.enforce_limit(&mut by_hash); + + // then + assert_eq!(by_hash.len(), 1); + assert_eq!(set.by_priority.len(), 1); + assert_eq!(set.by_address.len(), 1); + assert_eq!(set.by_priority.iter().next().unwrap().clone(), order1); + set.clear(); + assert_eq!(set.by_priority.len(), 0); + assert_eq!(set.by_address.len(), 0); + } + + #[test] + fn should_replace_transaction_in_set() { + let mut set = TransactionSet { + by_priority: BTreeSet::new(), + by_address: Table::new(), + limit: 1 + }; + // Create two transactions with same nonce + // (same hash) + let (tx1, tx2) = new_txs(U256::from(0)); + let tx1 = VerifiedTransaction::new(tx1).unwrap(); + let tx2 = VerifiedTransaction::new(tx2).unwrap(); + let by_hash = { + let mut x = HashMap::new(); + let tx1 = VerifiedTransaction::new(tx1.transaction.clone()).unwrap(); + let tx2 = VerifiedTransaction::new(tx2.transaction.clone()).unwrap(); + x.insert(tx1.hash(), tx1); + x.insert(tx2.hash(), tx2); + x + }; + // Insert both transactions + let order1 = TransactionOrder::for_transaction(&tx1, U256::zero()); + set.insert(tx1.sender(), tx1.nonce(), order1.clone()); + assert_eq!(set.by_priority.len(), 1); + assert_eq!(set.by_address.len(), 1); + // Two different orders (imagine nonce changed in the meantime) + let order2 = TransactionOrder::for_transaction(&tx2, U256::one()); + set.insert(tx2.sender(), tx2.nonce(), order2.clone()); + assert_eq!(set.by_priority.len(), 1); + assert_eq!(set.by_address.len(), 1); + + // then + assert_eq!(by_hash.len(), 1); + assert_eq!(set.by_priority.len(), 1); + assert_eq!(set.by_address.len(), 1); + assert_eq!(set.by_priority.iter().next().unwrap().clone(), order2); + } + + #[test] + fn should_handle_same_transaction_imported_twice_with_different_state_nonces() { + // given + let mut txq = TransactionQueue::new(); + let (tx, tx2) = new_similar_txs(); + let prev_nonce = |a: &Address| AccountDetails{ nonce: default_nonce(a).nonce - U256::one(), balance: + !U256::zero() }; + + // First insert one transaction to future + let res = txq.add(tx, &prev_nonce); + assert!(res.is_ok()); + assert_eq!(txq.status().future, 1); + + // now import second transaction to current + let res = txq.add(tx2.clone(), &default_nonce); + + // and then there should be only one transaction in current (the one with higher gas_price) + assert!(res.is_ok()); + assert_eq!(txq.status().pending, 1); + assert_eq!(txq.status().future, 0); + assert_eq!(txq.current.by_priority.len(), 1); + assert_eq!(txq.current.by_address.len(), 1); + assert_eq!(txq.top_transactions()[0], tx2); + } + + + #[test] + fn should_import_tx() { + // given + let mut txq = TransactionQueue::new(); + let tx = new_tx(); + + // when + let res = txq.add(tx, &default_nonce); + + // then + assert!(res.is_ok()); + let stats = txq.status(); + 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 + let mut txq = TransactionQueue::new(); + let tx = new_tx(); + txq.set_minimal_gas_price(tx.gas_price + U256::one()); + + // 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_reject_incorectly_signed_transaction() { + // given + let mut txq = TransactionQueue::new(); + let tx = new_unsigned_tx(U256::from(123)); + let stx = { + let mut s = RlpStream::new_list(9); + s.append(&tx.nonce); + s.append(&tx.gas_price); + s.append(&tx.gas); + s.append_empty_data(); // action=create + s.append(&tx.value); + s.append(&tx.data); + s.append(&0u64); // v + s.append(&U256::zero()); // r + s.append(&U256::zero()); // s + decode(s.as_raw()) + }; + // when + let res = txq.add(stx, &default_nonce); + + // then + assert!(res.is_err()); + } + + #[test] + fn should_import_txs_from_same_sender() { + // given + let mut txq = TransactionQueue::new(); + + let (tx, tx2) = new_txs(U256::from(1)); + + // when + txq.add(tx.clone(), &default_nonce).unwrap(); + txq.add(tx2.clone(), &default_nonce).unwrap(); + + // then + let top = txq.top_transactions(); + assert_eq!(top[0], tx); + assert_eq!(top[1], tx2); + assert_eq!(top.len(), 2); + } + + #[test] + fn should_return_pending_hashes() { + // given + let mut txq = TransactionQueue::new(); + + let (tx, tx2) = new_txs(U256::from(1)); + + // when + txq.add(tx.clone(), &default_nonce).unwrap(); + txq.add(tx2.clone(), &default_nonce).unwrap(); + + // then + let top = txq.pending_hashes(); + assert_eq!(top[0], tx.hash()); + assert_eq!(top[1], tx2.hash()); + assert_eq!(top.len(), 2); + } + + #[test] + fn should_put_transaction_to_futures_if_gap_detected() { + // given + let mut txq = TransactionQueue::new(); + + let (tx, tx2) = new_txs(U256::from(2)); + + // when + txq.add(tx.clone(), &default_nonce).unwrap(); + txq.add(tx2.clone(), &default_nonce).unwrap(); + + // then + let stats = txq.status(); + assert_eq!(stats.pending, 1); + assert_eq!(stats.future, 1); + let top = txq.top_transactions(); + assert_eq!(top.len(), 1); + assert_eq!(top[0], tx); + } + + #[test] + fn should_correctly_update_futures_when_removing() { + // given + 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(); + + let (tx, tx2) = new_txs(U256::from(1)); + txq.add(tx.clone(), &prev_nonce).unwrap(); + txq.add(tx2.clone(), &prev_nonce).unwrap(); + assert_eq!(txq.status().future, 2); + + // when + txq.remove(&tx.hash(), &next2_nonce); + // should remove both transactions since they are not valid + + // then + assert_eq!(txq.status().pending, 0); + assert_eq!(txq.status().future, 0); + } + + #[test] + fn should_move_transactions_if_gap_filled() { + // given + let mut txq = TransactionQueue::new(); + let kp = KeyPair::create().unwrap(); + let secret = kp.secret(); + let tx = new_unsigned_tx(U256::from(123)).sign(&secret); + let tx1 = new_unsigned_tx(U256::from(124)).sign(&secret); + let tx2 = new_unsigned_tx(U256::from(125)).sign(&secret); + + txq.add(tx, &default_nonce).unwrap(); + assert_eq!(txq.status().pending, 1); + txq.add(tx2, &default_nonce).unwrap(); + assert_eq!(txq.status().future, 1); + + // when + txq.add(tx1, &default_nonce).unwrap(); + + // then + let stats = txq.status(); + assert_eq!(stats.pending, 3); + assert_eq!(stats.future, 0); + } + + #[test] + fn should_remove_transaction() { + // given + let mut txq2 = TransactionQueue::new(); + let (tx, tx2) = new_txs(U256::from(3)); + txq2.add(tx.clone(), &default_nonce).unwrap(); + txq2.add(tx2.clone(), &default_nonce).unwrap(); + assert_eq!(txq2.status().pending, 1); + assert_eq!(txq2.status().future, 1); + + // when + txq2.remove(&tx.hash(), &default_nonce); + txq2.remove(&tx2.hash(), &default_nonce); + + + // then + let stats = txq2.status(); + assert_eq!(stats.pending, 0); + assert_eq!(stats.future, 0); + } + + #[test] + fn should_move_transactions_to_future_if_gap_introduced() { + // given + let mut txq = TransactionQueue::new(); + let (tx, tx2) = new_txs(U256::from(1)); + let tx3 = new_tx(); + txq.add(tx2.clone(), &default_nonce).unwrap(); + assert_eq!(txq.status().future, 1); + txq.add(tx3.clone(), &default_nonce).unwrap(); + txq.add(tx.clone(), &default_nonce).unwrap(); + assert_eq!(txq.status().pending, 3); + + // when + txq.remove(&tx.hash(), &default_nonce); + + // then + let stats = txq.status(); + assert_eq!(stats.future, 1); + assert_eq!(stats.pending, 1); + } + + #[test] + fn should_clear_queue() { + // given + let mut txq = TransactionQueue::new(); + let (tx, tx2) = new_txs(U256::one()); + + // add + txq.add(tx2.clone(), &default_nonce).unwrap(); + txq.add(tx.clone(), &default_nonce).unwrap(); + let stats = txq.status(); + assert_eq!(stats.pending, 2); + + // when + txq.clear(); + + // then + let stats = txq.status(); + assert_eq!(stats.pending, 0); + } + + #[test] + fn should_drop_old_transactions_when_hitting_the_limit() { + // given + let mut txq = TransactionQueue::with_limits(1, 1); + let (tx, tx2) = new_txs(U256::one()); + txq.add(tx.clone(), &default_nonce).unwrap(); + assert_eq!(txq.status().pending, 1); + + // when + txq.add(tx2.clone(), &default_nonce).unwrap(); + + // then + let t = txq.top_transactions(); + assert_eq!(txq.status().pending, 1); + assert_eq!(t.len(), 1); + assert_eq!(t[0], tx); + } + + #[test] + fn should_limit_future_transactions() { + let mut txq = TransactionQueue::with_limits(10, 1); + let (tx1, tx2) = new_txs(U256::from(4)); + let (tx3, tx4) = new_txs(U256::from(4)); + txq.add(tx1.clone(), &default_nonce).unwrap(); + txq.add(tx3.clone(), &default_nonce).unwrap(); + assert_eq!(txq.status().pending, 2); + + // when + txq.add(tx2.clone(), &default_nonce).unwrap(); + assert_eq!(txq.status().future, 1); + txq.add(tx4.clone(), &default_nonce).unwrap(); + + // then + assert_eq!(txq.status().future, 1); + } + + #[test] + fn should_drop_transactions_with_old_nonces() { + let mut txq = TransactionQueue::new(); + let tx = new_tx(); + let last_nonce = tx.nonce + U256::one(); + let fetch_last_nonce = |_a: &Address| AccountDetails{ nonce: last_nonce, balance: !U256::zero() }; + + // when + txq.add(tx, &fetch_last_nonce).unwrap_err(); + + // then + let stats = txq.status(); + assert_eq!(stats.pending, 0); + assert_eq!(stats.future, 0); + } + + #[test] + fn should_not_insert_same_transaction_twice() { + // given + 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(); + assert_eq!(txq.status().future, 1); + assert_eq!(txq.status().pending, 0); + + // when + txq.add(tx2.clone(), &nonce).unwrap_err(); + + // then + let stats = txq.status(); + assert_eq!(stats.future, 1); + assert_eq!(stats.pending, 0); + } + + #[test] + fn should_accept_same_transaction_twice_if_removed() { + // given + let mut txq = TransactionQueue::new(); + let (tx1, tx2) = new_txs(U256::from(1)); + txq.add(tx1.clone(), &default_nonce).unwrap(); + txq.add(tx2.clone(), &default_nonce).unwrap(); + assert_eq!(txq.status().pending, 2); + + // when + txq.remove(&tx1.hash(), &default_nonce); + assert_eq!(txq.status().pending, 0); + assert_eq!(txq.status().future, 1); + txq.add(tx1.clone(), &default_nonce).unwrap(); + + // then + let stats = txq.status(); + assert_eq!(stats.future, 0); + assert_eq!(stats.pending, 2); + } + + #[test] + fn should_not_move_to_future_if_state_nonce_is_higher() { + // given + 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(); + txq.add(tx2.clone(), &default_nonce).unwrap(); + assert_eq!(txq.status().future, 1); + txq.add(tx3.clone(), &default_nonce).unwrap(); + txq.add(tx.clone(), &default_nonce).unwrap(); + assert_eq!(txq.status().pending, 3); + + // when + txq.remove(&tx.hash(), &next_nonce); + + // then + let stats = txq.status(); + assert_eq!(stats.future, 0); + assert_eq!(stats.pending, 2); + } + + #[test] + fn should_replace_same_transaction_when_has_higher_fee() { + // given + let mut txq = TransactionQueue::new(); + let keypair = KeyPair::create().unwrap(); + let tx = new_unsigned_tx(U256::from(123)).sign(&keypair.secret()); + let tx2 = { + let mut tx2 = tx.deref().clone(); + tx2.gas_price = U256::from(200); + tx2.sign(&keypair.secret()) + }; + + // when + txq.add(tx, &default_nonce).unwrap(); + txq.add(tx2, &default_nonce).unwrap(); + + // then + let stats = txq.status(); + assert_eq!(stats.pending, 1); + assert_eq!(stats.future, 0); + assert_eq!(txq.top_transactions()[0].gas_price, U256::from(200)); + } + + #[test] + fn should_replace_same_transaction_when_importing_to_futures() { + // given + let mut txq = TransactionQueue::new(); + let keypair = KeyPair::create().unwrap(); + let tx0 = new_unsigned_tx(U256::from(123)).sign(&keypair.secret()); + let tx1 = { + let mut tx1 = tx0.deref().clone(); + tx1.nonce = U256::from(124); + tx1.sign(&keypair.secret()) + }; + let tx2 = { + let mut tx2 = tx1.deref().clone(); + tx2.gas_price = U256::from(200); + tx2.sign(&keypair.secret()) + }; + + // when + txq.add(tx1, &default_nonce).unwrap(); + txq.add(tx2, &default_nonce).unwrap(); + assert_eq!(txq.status().future, 1); + txq.add(tx0, &default_nonce).unwrap(); + + // then + let stats = txq.status(); + assert_eq!(stats.future, 0); + assert_eq!(stats.pending, 2); + 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| 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(); + txq.add(tx2, &previous_nonce).unwrap(); + assert_eq!(txq.status().future, 2); + + // when + txq.remove(&tx1.hash(), &next_nonce); + + // then + let stats = txq.status(); + assert_eq!(stats.future, 0); + assert_eq!(stats.pending, 1); + } +} diff --git a/parity/main.rs b/parity/main.rs index 460922b64..731bba9a1 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -17,70 +17,209 @@ //! Ethcore client application. #![warn(missing_docs)] -#![feature(plugin)] -#![plugin(docopt_macros)] -#![plugin(clippy)] +#![cfg_attr(feature="dev", feature(plugin))] +#![cfg_attr(feature="dev", plugin(clippy))] extern crate docopt; +extern crate num_cpus; extern crate rustc_serialize; extern crate ethcore_util as util; extern crate ethcore; extern crate ethsync; +extern crate ethminer; +#[macro_use] extern crate log as rlog; extern crate env_logger; extern crate ctrlc; extern crate fdlimit; -extern crate target_info; +extern crate daemonize; +extern crate time; +extern crate number_prefix; +extern crate rpassword; #[cfg(feature = "rpc")] extern crate ethcore_rpc as rpc; -use std::net::{SocketAddr}; +use std::net::{SocketAddr, IpAddr}; use std::env; -use rlog::{LogLevelFilter}; +use std::process::exit; +use std::path::PathBuf; use env_logger::LogBuilder; use ctrlc::CtrlC; use util::*; -use util::panics::MayPanic; +use util::panics::{MayPanic, ForwardPanic, PanicHandler}; +use util::keys::store::*; use ethcore::spec::*; use ethcore::client::*; use ethcore::service::{ClientService, NetSyncMessage}; use ethcore::ethereum; -use ethcore::blockchain::CacheSize; -use ethsync::EthSync; -use target_info::Target; +use ethsync::{EthSync, SyncConfig, SyncProvider}; +use ethminer::{Miner, MinerService}; +use docopt::Docopt; +use daemonize::Daemonize; +use number_prefix::{binary_prefix, Standalone, Prefixed}; -docopt!(Args derive Debug, " +fn die_with_message(msg: &str) -> ! { + println!("ERROR: {}", msg); + exit(1); +} + +#[macro_export] +macro_rules! die { + ($($arg:tt)*) => (die_with_message(&format!("{}", format_args!($($arg)*)))); +} + +const USAGE: &'static str = r#" Parity. Ethereum Client. By Wood/Paronyan/Kotewicz/DrwiÄ™ga/Volf. Copyright 2015, 2016 Ethcore (UK) Limited Usage: - parity [options] [ --no-bootstrap | ... ] + parity daemon [options] + parity account (new | list) + parity [options] -Options: - --chain CHAIN Specify the blockchain type. CHAIN may be either a JSON chain specification file - or frontier, mainnet, morden, or testnet [default: frontier]. - -d --db-path PATH Specify the database & configuration directory path [default: $HOME/.parity] +Protocol Options: + --chain CHAIN Specify the blockchain type. CHAIN may be either a + JSON chain specification file or olympic, frontier, + homestead, mainnet, morden, or testnet + [default: homestead]. + -d --db-path PATH Specify the database & configuration directory path + [default: $HOME/.parity]. + --keys-path PATH Specify the path for JSON key files to be found + [default: $HOME/.web3/keys]. + --identity NAME Specify your node's name. - --no-bootstrap Don't bother trying to connect to any nodes initially. - --listen-address URL Specify the IP/port on which to listen for peers [default: 0.0.0.0:30304]. - --public-address URL Specify the IP/port on which peers may connect [default: 0.0.0.0:30304]. - --address URL Equivalent to --listen-address URL --public-address URL. - --upnp Use UPnP to try to figure out the correct network settings. - --node-key KEY Specify node secret key as hex string. - - --cache-pref-size BYTES Specify the prefered size of the blockchain cache in bytes [default: 16384]. - --cache-max-size BYTES Specify the maximum size of the blockchain cache in bytes [default: 262144]. +Networking Options: + --port PORT Override the port on which the node should listen + [default: 30303]. + --peers NUM Try to maintain that many peers [default: 25]. + --nat METHOD Specify method to use for determining public + address. Must be one of: any, none, upnp, + extip: [default: any]. + --network-id INDEX Override the network identifier from the chain we + are on. + --bootnodes NODES Override the bootnodes from our chain. NODES should + be comma-delimited enodes. + --no-discovery Disable new peer discovery. + --node-key KEY Specify node secret key, either as 64-character hex + string or input to SHA3 operation. +API and Console Options: -j --jsonrpc Enable the JSON-RPC API sever. - --jsonrpc-url URL Specify URL for JSON-RPC API server [default: 127.0.0.1:8545]. + --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 + [default: null]. + --jsonrpc-apis APIS Specify the APIs available through the JSONRPC + interface. APIS is a comma-delimited list of API + name. Possible name are web3, eth and net. + [default: web3,eth,net,personal]. - -l --logging LOGGING Specify the logging level. +Sealing/Mining Options: + --gas-price WEI Minimum amount of Wei to be paid for a transaction + to be accepted for mining [default: 20000000000]. + --gas-floor-target GAS Amount of gas per block to target when sealing a new + block [default: 4712388]. + --author ADDRESS Specify the block author (aka "coinbase") address + for sending block rewards from sealed blocks + [default: 0037a6b811ffeb6e072da21179d11b1406371c63]. + --extra-data STRING Specify a custom extra-data for authored blocks, no + more than 32 characters. + +Footprint Options: + --pruning METHOD Configure pruning of the state/storage trie. METHOD + may be one of: archive, basic (experimental), fast + (experimental) [default: archive]. + --cache-pref-size BYTES Specify the prefered size of the blockchain cache in + bytes [default: 16384]. + --cache-max-size BYTES Specify the maximum size of the blockchain cache in + bytes [default: 262144]. + --queue-max-size BYTES Specify the maximum size of memory to use for block + queue [default: 52428800]. + --cache MEGABYTES Set total amount of discretionary memory to use for + the entire system, overrides other cache and queue + options. + +Geth-compatibility Options: + --datadir PATH Equivalent to --db-path PATH. + --testnet Equivalent to --chain testnet. + --networkid INDEX Equivalent to --network-id INDEX. + --maxpeers COUNT Equivalent to --peers COUNT. + --nodekey KEY Equivalent to --node-key KEY. + --nodiscover Equivalent to --no-discovery. + --rpc Equivalent to --jsonrpc. + --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. + --gasprice WEI Equivalent to --gas-price WEI. + --etherbase ADDRESS Equivalent to --author ADDRESS. + --extradata STRING Equivalent to --extra-data STRING. + +Miscellaneous Options: + -l --logging LOGGING Specify the logging level. Must conform to the same + format as RUST_LOG. -v --version Show information about version. -h --help Show this screen. -", flag_cache_pref_size: usize, flag_cache_max_size: usize, flag_address: Option, flag_node_key: Option); +"#; + +#[derive(Debug, RustcDecodable)] +struct Args { + cmd_daemon: bool, + cmd_account: bool, + cmd_new: bool, + cmd_list: bool, + arg_pid_file: String, + flag_chain: String, + flag_db_path: String, + flag_identity: String, + flag_cache: Option, + flag_keys_path: String, + flag_bootnodes: Option, + flag_network_id: Option, + flag_pruning: String, + flag_port: u16, + flag_peers: usize, + flag_no_discovery: bool, + flag_nat: String, + flag_node_key: Option, + flag_cache_pref_size: usize, + flag_cache_max_size: usize, + flag_queue_max_size: usize, + flag_jsonrpc: bool, + flag_jsonrpc_interface: String, + flag_jsonrpc_port: u16, + flag_jsonrpc_cors: String, + flag_jsonrpc_apis: String, + flag_author: String, + flag_gas_price: String, + flag_gas_floor_target: String, + flag_extra_data: Option, + flag_logging: Option, + flag_version: bool, + // geth-compatibility... + flag_nodekey: Option, + flag_nodiscover: bool, + flag_maxpeers: Option, + flag_datadir: Option, + flag_extradata: Option, + flag_etherbase: Option, + flag_gasprice: Option, + flag_rpc: bool, + flag_rpcaddr: Option, + flag_rpcport: Option, + flag_rpccorsdomain: Option, + flag_rpcapi: Option, + flag_testnet: bool, + flag_networkid: Option, +} + +fn setup_log(init: &Option) { + use rlog::*; -fn setup_log(init: &str) { let mut builder = LogBuilder::new(); builder.filter(None, LogLevelFilter::Info); @@ -88,37 +227,76 @@ fn setup_log(init: &str) { builder.parse(&env::var("RUST_LOG").unwrap()); } - builder.parse(init); + if let Some(ref s) = *init { + builder.parse(s); + } + let format = |record: &LogRecord| { + let timestamp = time::strftime("%Y-%m-%d %H:%M:%S %Z", &time::now()).unwrap(); + if max_log_level() <= LogLevelFilter::Info { + format!("{}{}", timestamp, record.args()) + } else { + format!("{}{}:{}: {}", timestamp, record.level(), record.target(), record.args()) + } + }; + builder.format(format); builder.init().unwrap(); } #[cfg(feature = "rpc")] -fn setup_rpc_server(client: Arc, sync: Arc, url: &str) { +fn setup_rpc_server( + client: Arc, + sync: Arc, + secret_store: Arc, + miner: Arc, + url: &str, + cors_domain: &str, + apis: Vec<&str> +) -> Option> { use rpc::v1::*; - let mut server = rpc::HttpServer::new(1); - server.add_delegate(Web3Client::new().to_delegate()); - server.add_delegate(EthClient::new(client.clone(), sync.clone()).to_delegate()); - server.add_delegate(EthFilterClient::new(client).to_delegate()); - server.add_delegate(NetClient::new(sync).to_delegate()); - server.start_async(url); + let server = rpc::RpcServer::new(); + for api in apis.into_iter() { + match api { + "web3" => server.add_delegate(Web3Client::new().to_delegate()), + "net" => server.add_delegate(NetClient::new(&sync).to_delegate()), + "eth" => { + server.add_delegate(EthClient::new(&client, &sync, &secret_store, &miner).to_delegate()); + server.add_delegate(EthFilterClient::new(&client, &miner).to_delegate()); + } + "personal" => server.add_delegate(PersonalClient::new(&secret_store).to_delegate()), + _ => { + die!("{}: Invalid API name to be enabled.", api); + } + } + } + Some(server.start_http(url, cors_domain, ::num_cpus::get())) } #[cfg(not(feature = "rpc"))] -fn setup_rpc_server(_client: Arc, _sync: Arc, _url: &str) { +fn setup_rpc_server( + _client: Arc, + _sync: Arc, + _secret_store: Arc, + _miner: Arc, + _url: &str, + _cors_domain: &str, + _apis: Vec<&str> +) -> Option> { + None } fn print_version() { println!("\ -Parity version {} ({}-{}-{}) +Parity + version {} Copyright 2015, 2016 Ethcore (UK) Limited License GPLv3+: GNU GPL version 3 or later . This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. By Wood/Paronyan/Kotewicz/DrwiÄ™ga/Volf.\ -", env!("CARGO_PKG_VERSION"), Target::arch(), Target::env(), Target::os()); +", version()); } struct Configuration { @@ -128,114 +306,287 @@ struct Configuration { impl Configuration { fn parse() -> Self { Configuration { - args: Args::docopt().decode().unwrap_or_else(|e| e.exit()) + args: Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit()), } } fn path(&self) -> String { - self.args.flag_db_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) + let d = self.args.flag_datadir.as_ref().unwrap_or(&self.args.flag_db_path); + d.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) + } + + fn author(&self) -> Address { + let d = self.args.flag_etherbase.as_ref().unwrap_or(&self.args.flag_author); + 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) + }) + } + + fn gas_floor_target(&self) -> U256 { + let d = &self.args.flag_gas_floor_target; + U256::from_dec_str(d).unwrap_or_else(|_| { + die!("{}: Invalid target gas floor given. Must be a decimal unsigned 256-bit number.", d) + }) + } + + fn gas_price(&self) -> U256 { + let d = self.args.flag_gasprice.as_ref().unwrap_or(&self.args.flag_gas_price); + U256::from_dec_str(d).unwrap_or_else(|_| { + die!("{}: Invalid gas price given. Must be a decimal unsigned 256-bit number.", d) + }) + } + + fn extra_data(&self) -> Bytes { + match self.args.flag_extradata.as_ref().or(self.args.flag_extra_data.as_ref()) { + Some(ref x) if x.len() <= 32 => x.as_bytes().to_owned(), + None => version_data(), + Some(ref x) => { die!("{}: Extra data must be at most 32 characters.", x); } + } + } + + fn _keys_path(&self) -> String { + self.args.flag_keys_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) } fn spec(&self) -> Spec { + if self.args.flag_testnet { + return ethereum::new_morden(); + } match self.args.flag_chain.as_ref() { - "frontier" | "mainnet" => ethereum::new_frontier(), + "frontier" | "homestead" | "mainnet" => ethereum::new_frontier(), "morden" | "testnet" => ethereum::new_morden(), "olympic" => ethereum::new_olympic(), - f => Spec::from_json_utf8(contents(f).expect("Couldn't read chain specification file. Sure it exists?").as_ref()), + f => Spec::from_json_utf8(contents(f).unwrap_or_else(|_| { + die!("{}: Couldn't read chain specification file. Sure it exists?", f) + }).as_ref()), + } + } + + fn normalize_enode(e: &str) -> Option { + if is_valid_node_url(e) { + Some(e.to_owned()) + } else { + None } } fn init_nodes(&self, spec: &Spec) -> Vec { - if self.args.flag_no_bootstrap { Vec::new() } else { - match self.args.arg_enode.len() { - 0 => spec.nodes().clone(), - _ => self.args.arg_enode.clone(), + match self.args.flag_bootnodes { + 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) + }) + }).collect(), + Some(_) => Vec::new(), + None => spec.nodes().clone(), + } + } + + #[cfg_attr(feature="dev", allow(useless_format))] + fn net_addresses(&self) -> (Option, Option) { + let listen_address = Some(SocketAddr::new(IpAddr::from_str("0.0.0.0").unwrap(), self.args.flag_port)); + let public_address = if self.args.flag_nat.starts_with("extip:") { + let host = &self.args.flag_nat[6..]; + let host = IpAddr::from_str(host).unwrap_or_else(|_| die!("Invalid host given with `--nat extip:{}`", host)); + Some(SocketAddr::new(host, self.args.flag_port)) + } else { + listen_address + }; + (listen_address, public_address) + } + + fn net_settings(&self, spec: &Spec) -> NetworkConfiguration { + let mut ret = NetworkConfiguration::new(); + ret.nat_enabled = self.args.flag_nat == "any" || self.args.flag_nat == "upnp"; + ret.boot_nodes = self.init_nodes(spec); + let (listen, public) = self.net_addresses(); + ret.listen_address = listen; + ret.public_address = public; + ret.use_secret = self.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).unwrap_or_else(|_| s.sha3())); + ret.discovery_enabled = !self.args.flag_no_discovery && !self.args.flag_nodiscover; + ret.ideal_peers = self.args.flag_maxpeers.unwrap_or(self.args.flag_peers) as u32; + let mut net_path = PathBuf::from(&self.path()); + net_path.push("network"); + ret.config_path = Some(net_path.to_str().unwrap().to_owned()); + ret + } + + #[cfg_attr(feature="dev", allow(useless_format))] + fn client_config(&self) -> ClientConfig { + let mut client_config = ClientConfig::default(); + match self.args.flag_cache { + Some(mb) => { + client_config.blockchain.max_cache_size = mb * 1024 * 1024; + client_config.blockchain.pref_cache_size = client_config.blockchain.max_cache_size * 3 / 4; + } + None => { + client_config.blockchain.pref_cache_size = self.args.flag_cache_pref_size; + client_config.blockchain.max_cache_size = self.args.flag_cache_max_size; + } + } + client_config.pruning = match self.args.flag_pruning.as_str() { + "archive" => journaldb::Algorithm::Archive, + "light" => journaldb::Algorithm::EarlyMerge, + "fast" => journaldb::Algorithm::OverlayRecent, + "basic" => journaldb::Algorithm::RefCounted, + _ => { die!("Invalid pruning method given."); } + }; + client_config.name = self.args.flag_identity.clone(); + client_config.queue.max_mem_use = self.args.flag_queue_max_size; + client_config + } + + fn sync_config(&self, spec: &Spec) -> SyncConfig { + let mut sync_config = SyncConfig::default(); + sync_config.network_id = self.args.flag_network_id.as_ref().or(self.args.flag_networkid.as_ref()).map_or(spec.network_id(), |id| { + U256::from_str(id).unwrap_or_else(|_| die!("{}: Invalid index given with --network-id/--networkid", id)) + }); + sync_config + } + + fn execute(&self) { + if self.args.flag_version { + print_version(); + return; + } + if self.args.cmd_daemon { + Daemonize::new() + .pid_file(self.args.arg_pid_file.clone()) + .chown_pid_file(true) + .start() + .unwrap_or_else(|e| die!("Couldn't daemonize; {}", e)); + } + if self.args.cmd_account { + self.execute_account_cli(); + return; + } + self.execute_client(); + } + + fn execute_account_cli(&self) { + use util::keys::store::SecretStore; + use rpassword::read_password; + let mut secret_store = SecretStore::new(); + if self.args.cmd_new { + println!("Please note that password is NOT RECOVERABLE."); + println!("Type password: "); + let password = read_password().unwrap(); + println!("Repeat password: "); + let password_repeat = read_password().unwrap(); + if password != password_repeat { + println!("Passwords do not match!"); + return; + } + println!("New account address:"); + let new_address = secret_store.new_account(&password).unwrap(); + println!("{:?}", new_address); + return; + } + if self.args.cmd_list { + println!("Known addresses:"); + for &(addr, _) in &secret_store.accounts().unwrap() { + println!("{:?}", addr); } } } - fn net_addresses(&self) -> (SocketAddr, SocketAddr) { - let listen_address; - let public_address; + #[cfg_attr(feature="dev", allow(useless_format))] + fn execute_client(&self) { + // Setup panic handler + let panic_handler = PanicHandler::new_in_arc(); - match self.args.flag_address { - None => { - listen_address = SocketAddr::from_str(self.args.flag_listen_address.as_ref()).expect("Invalid listen address given with --listen-address"); - public_address = SocketAddr::from_str(self.args.flag_public_address.as_ref()).expect("Invalid public address given with --public-address"); - } - Some(ref a) => { - public_address = SocketAddr::from_str(a.as_ref()).expect("Invalid listen/public address given with --address"); - listen_address = public_address; - } - }; + // Setup logging + setup_log(&self.args.flag_logging); + // Raise fdlimit + unsafe { ::fdlimit::raise_fd_limit(); } - (listen_address, public_address) + let spec = self.spec(); + let net_settings = self.net_settings(&spec); + let sync_config = self.sync_config(&spec); + + // Build client + let mut service = ClientService::start(self.client_config(), spec, net_settings, &Path::new(&self.path())).unwrap(); + panic_handler.forward_from(&service); + let client = service.client(); + + // Miner + let miner = Miner::new(); + miner.set_author(self.author()); + miner.set_gas_floor_target(self.gas_floor_target()); + miner.set_extra_data(self.extra_data()); + miner.set_minimal_gas_price(self.gas_price()); + + // Sync + let sync = EthSync::register(service.network(), sync_config, client.clone(), miner.clone()); + + // Secret Store + let account_service = Arc::new(AccountService::new()); + + // Setup rpc + if self.args.flag_jsonrpc || self.args.flag_rpc { + let url = format!("{}:{}", + 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)); + let cors = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors); + // TODO: use this as the API list. + let apis = self.args.flag_rpcapi.as_ref().unwrap_or(&self.args.flag_jsonrpc_apis); + let server_handler = setup_rpc_server( + service.client(), + sync.clone(), + account_service.clone(), + miner.clone(), + &url, + cors, + apis.split(',').collect() + ); + if let Some(handler) = server_handler { + panic_handler.forward_from(handler.deref()); + } + } + + // Register IO handler + let io_handler = Arc::new(ClientIoHandler { + client: service.client(), + info: Default::default(), + sync: sync.clone(), + accounts: account_service.clone(), + }); + service.io().register_handler(io_handler).expect("Error registering IO handler"); + + // Handle exit + wait_for_exit(panic_handler); } } -fn wait_for_exit(client_service: &ClientService) { +fn wait_for_exit(panic_handler: Arc) { let exit = Arc::new(Condvar::new()); + // Handle possible exits let e = exit.clone(); CtrlC::set_handler(move || { e.notify_all(); }); + + // Handle panics let e = exit.clone(); - client_service.on_panic(move |_reason| { e.notify_all(); }); + panic_handler.on_panic(move |_reason| { e.notify_all(); }); + // Wait for signal let mutex = Mutex::new(()); let _ = exit.wait(mutex.lock().unwrap()).unwrap(); } fn main() { - let conf = Configuration::parse(); - if conf.args.flag_version { - print_version(); - return; - } - - let spec = conf.spec(); - - // Setup logging - setup_log(&conf.args.flag_logging); - // Raise fdlimit - unsafe { ::fdlimit::raise_fd_limit(); } - - // Configure network - let mut net_settings = NetworkConfiguration::new(); - net_settings.nat_enabled = conf.args.flag_upnp; - net_settings.boot_nodes = conf.init_nodes(&spec); - let (listen, public) = conf.net_addresses(); - net_settings.listen_address = listen; - net_settings.public_address = public; - net_settings.use_secret = conf.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).expect("Invalid key string")); - - // Build client - let mut service = ClientService::start(spec, net_settings, &Path::new(&conf.path())).unwrap(); - let client = service.client().clone(); - client.configure_cache(conf.args.flag_cache_pref_size, conf.args.flag_cache_max_size); - - // Sync - let sync = EthSync::register(service.network(), client); - - // Setup rpc - if conf.args.flag_jsonrpc { - setup_rpc_server(service.client(), sync.clone(), &conf.args.flag_jsonrpc_url); - } - - // Register IO handler - let io_handler = Arc::new(ClientIoHandler { - client: service.client(), - info: Default::default(), - sync: sync - }); - service.io().register_handler(io_handler).expect("Error registering IO handler"); - - // Handle exit - wait_for_exit(&service); + Configuration::parse().execute(); } struct Informant { chain_info: RwLock>, - cache_info: RwLock>, + cache_info: RwLock>, report: RwLock>, } @@ -250,18 +601,31 @@ impl Default for Informant { } impl Informant { + fn format_bytes(b: usize) -> String { + match binary_prefix(b as f64) { + Standalone(bytes) => format!("{} bytes", bytes), + Prefixed(prefix, n) => format!("{:.0} {}B", n, prefix), + } + } + pub fn tick(&self, client: &Client, sync: &EthSync) { // 5 seconds betwen calls. TODO: calculate this properly. let dur = 5usize; let chain_info = client.chain_info(); let queue_info = client.queue_info(); - let cache_info = client.cache_info(); - let report = client.report(); + let cache_info = client.blockchain_cache_info(); let sync_info = sync.status(); - if let (_, &Some(ref last_cache_info), &Some(ref last_report)) = (self.chain_info.read().unwrap().deref(), self.cache_info.read().unwrap().deref(), self.report.read().unwrap().deref()) { - println!("[ #{} {} ]---[ {} blk/s | {} tx/s | {} gas/s //··· {}/{} peers, #{}, {}+{} queued ···// {} ({}) bl {} ({}) ex ]", + let mut write_report = self.report.write().unwrap(); + let report = client.report(); + + if let (_, _, &Some(ref last_report)) = ( + self.chain_info.read().unwrap().deref(), + self.cache_info.read().unwrap().deref(), + write_report.deref() + ) { + println!("[ #{} {} ]---[ {} blk/s | {} tx/s | {} gas/s //··· {}/{} peers, #{}, {}+{} queued ···// mem: {} db, {} chain, {} queue, {} sync ]", chain_info.best_block_number, chain_info.best_block_hash, (report.blocks_imported - last_report.blocks_imported) / dur, @@ -274,35 +638,43 @@ impl Informant { queue_info.unverified_queue_size, queue_info.verified_queue_size, - cache_info.blocks, - cache_info.blocks as isize - last_cache_info.blocks as isize, - cache_info.block_details, - cache_info.block_details as isize - last_cache_info.block_details as isize + Informant::format_bytes(report.state_db_mem), + Informant::format_bytes(cache_info.total()), + Informant::format_bytes(queue_info.mem_used), + Informant::format_bytes(sync_info.mem_used), ); } *self.chain_info.write().unwrap().deref_mut() = Some(chain_info); *self.cache_info.write().unwrap().deref_mut() = Some(cache_info); - *self.report.write().unwrap().deref_mut() = Some(report); + *write_report.deref_mut() = Some(report); } } const INFO_TIMER: TimerToken = 0; +const ACCOUNT_TICK_TIMER: TimerToken = 10; +const ACCOUNT_TICK_MS: u64 = 60000; + struct ClientIoHandler { client: Arc, sync: Arc, + accounts: Arc, info: Informant, } impl IoHandler for ClientIoHandler { fn initialize(&self, io: &IoContext) { io.register_timer(INFO_TIMER, 5000).expect("Error registering timer"); + io.register_timer(ACCOUNT_TICK_TIMER, ACCOUNT_TICK_MS).expect("Error registering account timer"); + } fn timeout(&self, _io: &IoContext, timer: TimerToken) { - if INFO_TIMER == timer { - self.info.tick(&self.client, &self.sync); + match timer { + INFO_TIMER => { self.info.tick(&self.client, &self.sync); } + ACCOUNT_TICK_TIMER => { self.accounts.tick(); }, + _ => {} } } } diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 0bb255d98..c28f598fd 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -1,21 +1,34 @@ [package] description = "Ethcore jsonrpc" name = "ethcore-rpc" -version = "0.9.0" +version = "1.1.0" license = "GPL-3.0" authors = ["Ethcore . + +#[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/v1/types/mod.rs.in"); + let dst = Path::new(&out_dir).join("mod.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/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/lib.rs b/rpc/src/lib.rs index 0b148c983..3096a45c9 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -16,12 +16,12 @@ //! Ethcore rpc. #![warn(missing_docs)] -#![feature(custom_derive, custom_attribute, plugin)] -#![plugin(serde_macros)] -#![plugin(clippy)] +#![cfg_attr(feature="nightly", feature(custom_derive, custom_attribute, plugin))] +#![cfg_attr(feature="nightly", plugin(serde_macros, clippy))] +#[macro_use] +extern crate log; extern crate rustc_serialize; -extern crate target_info; extern crate serde; extern crate serde_json; extern crate jsonrpc_core; @@ -29,39 +29,46 @@ extern crate jsonrpc_http_server; extern crate ethcore_util as util; extern crate ethcore; extern crate ethsync; +extern crate ethminer; +extern crate transient_hashmap; +use std::sync::Arc; +use std::thread; +use util::panics::PanicHandler; use self::jsonrpc_core::{IoHandler, IoDelegate}; pub mod v1; /// Http server. -pub struct HttpServer { - handler: IoHandler, - threads: usize +pub struct RpcServer { + handler: Arc, } -impl HttpServer { +impl RpcServer { /// Construct new http server object with given number of threads. - pub fn new(threads: usize) -> HttpServer { - HttpServer { - handler: IoHandler::new(), - threads: threads + pub fn new() -> RpcServer { + RpcServer { + handler: Arc::new(IoHandler::new()), } } /// Add io delegate. - pub fn add_delegate(&mut self, delegate: IoDelegate) where D: Send + Sync + 'static { + pub fn add_delegate(&self, delegate: IoDelegate) where D: Send + Sync + 'static { self.handler.add_delegate(delegate); } - /// Start server asynchronously in new thread - pub fn start_async(self, addr: &str) { - let server = jsonrpc_http_server::Server::new(self.handler, self.threads); - server.start_async(addr) + /// Start server asynchronously in new thread and returns panic handler. + pub fn start_http(&self, addr: &str, cors_domain: &str, threads: usize) -> Arc { + let addr = addr.to_owned(); + let cors_domain = cors_domain.to_owned(); + let panic_handler = PanicHandler::new_in_arc(); + let ph = panic_handler.clone(); + let server = jsonrpc_http_server::Server::new(self.handler.clone()); + thread::Builder::new().name("jsonrpc_http".to_string()).spawn(move || { + ph.catch_panic(move || { + server.start(addr.as_ref(), jsonrpc_http_server::AccessControlAllowOrigin::Value(cors_domain), threads); + }).unwrap() + }).expect("Error while creating jsonrpc http thread"); + panic_handler } } - -/// Lib needs at least 1 test to generate coverage reports correctly. -#[test] -fn if_works() { -} diff --git a/rpc/src/v1/helpers/external_miner.rs b/rpc/src/v1/helpers/external_miner.rs new file mode 100644 index 000000000..4cbda8928 --- /dev/null +++ b/rpc/src/v1/helpers/external_miner.rs @@ -0,0 +1,59 @@ +// 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 std::collections::HashMap; +use std::sync::RwLock; +use util::numbers::U256; +use util::hash::H256; + +/// External miner interface. +pub trait ExternalMinerService: Send + Sync { + /// Submit hashrate for given miner. + fn submit_hashrate(&self, hashrate: U256, id: H256); + + /// Total hashrate. + fn hashrate(&self) -> U256; + + /// Returns true if external miner is mining. + fn is_mining(&self) -> bool; +} + +/// External Miner. +pub struct ExternalMiner { + hashrates: RwLock>, +} + +impl Default for ExternalMiner { + fn default() -> Self { + ExternalMiner { + hashrates: RwLock::new(HashMap::new()), + } + } +} + +impl ExternalMinerService for ExternalMiner { + fn submit_hashrate(&self, hashrate: U256, id: H256) { + self.hashrates.write().unwrap().insert(id, hashrate); + } + + fn hashrate(&self) -> U256 { + self.hashrates.read().unwrap().iter().fold(U256::from(0), |sum, (_, v)| sum + *v) + } + + fn is_mining(&self) -> bool { + !self.hashrates.read().unwrap().is_empty() + } +} diff --git a/rpc/src/v1/helpers/mod.rs b/rpc/src/v1/helpers/mod.rs new file mode 100644 index 000000000..8c574cff6 --- /dev/null +++ b/rpc/src/v1/helpers/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 . + +mod poll_manager; +mod poll_filter; +pub mod external_miner; + +pub use self::poll_manager::PollManager; +pub use self::poll_filter::PollFilter; +pub use self::external_miner::{ExternalMinerService, ExternalMiner}; diff --git a/rpc/src/v1/helpers/poll_filter.rs b/rpc/src/v1/helpers/poll_filter.rs new file mode 100644 index 000000000..f9ed6230c --- /dev/null +++ b/rpc/src/v1/helpers/poll_filter.rs @@ -0,0 +1,13 @@ +//! Helper type with all filter possibilities. + +use util::hash::H256; +use ethcore::filter::Filter; + +pub type BlockNumber = u64; + +#[derive(Clone)] +pub enum PollFilter { + Block(BlockNumber), + PendingTransaction(Vec), + Logs(BlockNumber, Filter) +} diff --git a/rpc/src/v1/helpers/poll_manager.rs b/rpc/src/v1/helpers/poll_manager.rs new file mode 100644 index 000000000..9735d7d5d --- /dev/null +++ b/rpc/src/v1/helpers/poll_manager.rs @@ -0,0 +1,127 @@ +// 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 . + +//! Indexes all rpc poll requests. + +use transient_hashmap::{TransientHashMap, Timer, StandardTimer}; + +/// Lifetime of poll (in seconds). +const POLL_LIFETIME: u64 = 60; + +pub type PollId = usize; + +/// Indexes all poll requests. +/// +/// Lazily garbage collects unused polls info. +pub struct PollManager where T: Timer { + polls: TransientHashMap, + next_available_id: PollId, +} + +impl PollManager { + /// Creates new instance of indexer. + pub fn new() -> Self { + PollManager::new_with_timer(Default::default()) + } +} + +impl PollManager where T: Timer { + + pub fn new_with_timer(timer: T) -> Self { + PollManager { + polls: TransientHashMap::new_with_timer(POLL_LIFETIME, timer), + next_available_id: 0, + } + } + + /// Returns id which can be used for new poll. + /// + /// Stores information when last poll happend. + pub fn create_poll(&mut self, filter: F) -> PollId { + self.polls.prune(); + + let id = self.next_available_id; + self.polls.insert(id, filter); + + self.next_available_id += 1; + id + } + + // Implementation is always using `poll_mut` + #[cfg(test)] + /// Get a reference to stored poll filter + pub fn poll(&mut self, id: &PollId) -> Option<&F> { + self.polls.prune(); + self.polls.get(id) + } + + /// Get a mutable reference to stored poll filter + pub fn poll_mut(&mut self, id: &PollId) -> Option<&mut F> { + self.polls.prune(); + self.polls.get_mut(id) + } + + /// Removes poll info. + pub fn remove_poll(&mut self, id: &PollId) { + self.polls.remove(id); + } +} + +#[cfg(test)] +mod tests { + use std::cell::Cell; + use transient_hashmap::Timer; + use v1::helpers::PollManager; + + struct TestTimer<'a> { + time: &'a Cell, + } + + impl<'a> Timer for TestTimer<'a> { + fn get_time(&self) -> i64 { + self.time.get() + } + } + + #[test] + fn test_poll_indexer() { + let time = Cell::new(0); + let timer = TestTimer { + time: &time, + }; + + let mut indexer = PollManager::new_with_timer(timer); + assert_eq!(indexer.create_poll(20), 0); + assert_eq!(indexer.create_poll(20), 1); + + time.set(10); + *indexer.poll_mut(&0).unwrap() = 21; + assert_eq!(*indexer.poll(&0).unwrap(), 21); + assert_eq!(*indexer.poll(&1).unwrap(), 20); + + time.set(30); + *indexer.poll_mut(&1).unwrap() = 23; + assert_eq!(*indexer.poll(&1).unwrap(), 23); + + time.set(75); + assert!(indexer.poll(&0).is_none()); + assert_eq!(*indexer.poll(&1).unwrap(), 23); + + indexer.remove_poll(&1); + assert!(indexer.poll(&1).is_none()); + } + +} diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index b595139f9..a065392d5 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -15,35 +15,83 @@ // along with Parity. If not, see . //! Eth rpc implementation. -use std::sync::Arc; -use ethsync::{EthSync, SyncState}; +use std::collections::HashSet; +use std::sync::{Arc, Weak, Mutex}; +use std::ops::Deref; +use ethsync::{SyncProvider, SyncState}; +use ethminer::{MinerService, AccountDetails}; use jsonrpc_core::*; -use util::hash::*; -use util::uint::*; +use util::numbers::*; use util::sha3::*; +use util::rlp::{encode, UntrustedRlp, View}; +use util::crypto::KeyPair; use ethcore::client::*; +use ethcore::block::IsBlock; use ethcore::views::*; +use ethcore::ethereum::Ethash; use ethcore::ethereum::denominations::shannon; +use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action}; use v1::traits::{Eth, EthFilter}; -use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, OptionalValue, Index}; +use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, CallRequest, OptionalValue, Index, Filter, Log, Receipt}; +use v1::helpers::{PollFilter, PollManager, ExternalMinerService, ExternalMiner}; +use util::keys::store::AccountProvider; -/// Eth rpc implementation. -pub struct EthClient { - client: Arc, - sync: Arc +fn default_gas() -> U256 { + U256::from(21_000) } -impl EthClient { +fn default_gas_price() -> U256 { + shannon() * U256::from(50) +} + +/// Eth rpc implementation. +pub struct EthClient + where C: BlockChainClient, + S: SyncProvider, + A: AccountProvider, + M: MinerService, + EM: ExternalMinerService { + client: Weak, + sync: Weak, + accounts: Weak, + miner: Weak, + external_miner: EM, +} + +impl EthClient + where C: BlockChainClient, + S: SyncProvider, + A: AccountProvider, + M: MinerService { + /// Creates new EthClient. - pub fn new(client: Arc, sync: Arc) -> Self { + pub fn new(client: &Arc, sync: &Arc, accounts: &Arc, miner: &Arc) -> Self { + EthClient::new_with_external_miner(client, sync, accounts, miner, ExternalMiner::default()) + } +} + +impl EthClient + where C: BlockChainClient, + S: SyncProvider, + A: AccountProvider, + M: MinerService, + EM: ExternalMinerService { + + /// Creates new EthClient with custom external miner. + pub fn new_with_external_miner(client: &Arc, sync: &Arc, accounts: &Arc, miner: &Arc, em: EM) + -> EthClient { EthClient { - client: client, - sync: sync + client: Arc::downgrade(client), + sync: Arc::downgrade(sync), + miner: Arc::downgrade(miner), + accounts: Arc::downgrade(accounts), + external_miner: em, } } fn block(&self, id: BlockId, include_txs: bool) -> Result { - match (self.client.block(id.clone()), self.client.block_total_difficulty(id)) { + let client = take_weak!(self.client); + match (client.block(id.clone()), client.block_total_difficulty(id)) { (Some(bytes), Some(total_difficulty)) => { let block_view = BlockView::new(&bytes); let view = block_view.header_view(); @@ -63,7 +111,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()) @@ -71,26 +120,93 @@ impl EthClient { BlockTransactions::Hashes(block_view.transaction_hashes()) } }, - extra_data: Bytes::default() + extra_data: Bytes::new(view.extra_data()) }; to_value(&block) }, _ => Ok(Value::Null) } } - + fn transaction(&self, id: TransactionId) -> Result { - match self.client.transaction(id) { + match take_weak!(self.client).transaction(id) { Some(t) => to_value(&Transaction::from(t)), None => Ok(Value::Null) } } + + fn uncle(&self, id: UncleId) -> Result { + let client = take_weak!(self.client); + match client.uncle(id).and_then(|u| client.block_total_difficulty(BlockId::Hash(u.hash())).map(|diff| (diff, u))) { + Some((difficulty, uncle)) => { + let block = Block { + hash: OptionalValue::Value(uncle.hash()), + parent_hash: uncle.parent_hash, + uncles_hash: uncle.uncles_hash, + author: uncle.author, + miner: uncle.author, + state_root: uncle.state_root, + transactions_root: uncle.transactions_root, + number: OptionalValue::Value(U256::from(uncle.number)), + gas_used: uncle.gas_used, + gas_limit: uncle.gas_limit, + logs_bloom: uncle.log_bloom, + timestamp: U256::from(uncle.timestamp), + difficulty: uncle.difficulty, + total_difficulty: difficulty, + receipts_root: uncle.receipts_root, + extra_data: Bytes::new(uncle.extra_data), + // todo: + nonce: H64::from(0), + uncles: vec![], + transactions: BlockTransactions::Hashes(vec![]), + }; + to_value(&block) + }, + None => Ok(Value::Null) + } + } + + fn sign_call(client: &Arc, accounts: &Arc, request: CallRequest) -> Option { + match request.from { + Some(ref from) => { + let transaction = EthTransaction { + nonce: request.nonce.unwrap_or_else(|| client.nonce(from)), + action: request.to.map_or(Action::Create, Action::Call), + gas: request.gas.unwrap_or_else(default_gas), + gas_price: request.gas_price.unwrap_or_else(default_gas_price), + value: request.value.unwrap_or_else(U256::zero), + data: request.data.map_or_else(Vec::new, |d| d.to_vec()) + }; + + accounts.account_secret(from).ok().map(|secret| transaction.sign(&secret)) + }, + None => { + let transaction = EthTransaction { + nonce: request.nonce.unwrap_or_else(U256::zero), + action: request.to.map_or(Action::Create, Action::Call), + gas: request.gas.unwrap_or_else(default_gas), + gas_price: request.gas_price.unwrap_or_else(default_gas_price), + value: request.value.unwrap_or_else(U256::zero), + data: request.data.map_or_else(Vec::new, |d| d.to_vec()) + }; + + KeyPair::create().ok().map(|kp| transaction.sign(kp.secret())) + } + } + } } -impl Eth for EthClient { +impl Eth for EthClient + where C: BlockChainClient + 'static, + S: SyncProvider + 'static, + A: AccountProvider + 'static, + M: MinerService + 'static, + EM: ExternalMinerService + 'static { + fn protocol_version(&self, params: Params) -> Result { match params { - Params::None => to_value(&U256::from(self.sync.status().protocol_version)), + Params::None => Ok(Value::String(format!("{}", take_weak!(self.sync).status().protocol_version).to_owned())), _ => Err(Error::invalid_params()) } } @@ -98,12 +214,12 @@ impl Eth for EthClient { fn syncing(&self, params: Params) -> Result { match params { Params::None => { - let status = self.sync.status(); + let status = take_weak!(self.sync).status(); let res = match status.state { SyncState::NotSynced | SyncState::Idle => SyncStatus::None, SyncState::Waiting | SyncState::Blocks | SyncState::NewBlocks => SyncStatus::Info(SyncInfo { starting_block: U256::from(status.start_block_number), - current_block: U256::from(self.client.chain_info().best_block_number), + current_block: U256::from(take_weak!(self.client).chain_info().best_block_number), highest_block: U256::from(status.highest_block_number.unwrap_or(status.start_block_number)) }) }; @@ -116,15 +232,15 @@ impl Eth for EthClient { // TODO: do not hardcode author. fn author(&self, params: Params) -> Result { match params { - Params::None => to_value(&Address::new()), - _ => Err(Error::invalid_params()) + Params::None => to_value(&take_weak!(self.miner).author()), + _ => Err(Error::invalid_params()), } } // TODO: return real value of mining once it's implemented. fn is_mining(&self, params: Params) -> Result { match params { - Params::None => Ok(Value::Bool(false)), + Params::None => to_value(&self.external_miner.is_mining()), _ => Err(Error::invalid_params()) } } @@ -132,45 +248,88 @@ impl Eth for EthClient { // TODO: return real hashrate once we have mining fn hashrate(&self, params: Params) -> Result { match params { - Params::None => to_value(&U256::zero()), + Params::None => to_value(&self.external_miner.hashrate()), _ => Err(Error::invalid_params()) } } fn gas_price(&self, params: Params) -> Result { match params { - Params::None => to_value(&(shannon() * U256::from(50))), + Params::None => to_value(&default_gas_price()), _ => Err(Error::invalid_params()) } } + fn accounts(&self, _: Params) -> Result { + let store = take_weak!(self.accounts); + match store.accounts() { + Ok(account_list) => to_value(&account_list), + Err(_) => Err(Error::internal_error()) + } + } + fn block_number(&self, params: Params) -> Result { match params { - Params::None => to_value(&U256::from(self.client.chain_info().best_block_number)), + Params::None => to_value(&U256::from(take_weak!(self.client).chain_info().best_block_number)), _ => Err(Error::invalid_params()) } } - fn block_transaction_count(&self, params: Params) -> Result { + fn balance(&self, params: Params) -> Result { + from_params::<(Address, BlockNumber)>(params) + .and_then(|(address, _block_number)| to_value(&take_weak!(self.client).balance(&address))) + } + + fn storage_at(&self, params: Params) -> Result { + from_params::<(Address, U256, BlockNumber)>(params) + .and_then(|(address, position, _block_number)| + to_value(&U256::from(take_weak!(self.client).storage_at(&address, &H256::from(position))))) + } + + fn transaction_count(&self, params: Params) -> Result { + from_params::<(Address, BlockNumber)>(params) + .and_then(|(address, _block_number)| to_value(&take_weak!(self.client).nonce(&address))) + } + + fn block_transaction_count_by_hash(&self, params: Params) -> Result { from_params::<(H256,)>(params) - .and_then(|(hash,)| match self.client.block(BlockId::Hash(hash)) { - Some(bytes) => to_value(&BlockView::new(&bytes).transactions_count()), - None => Ok(Value::Null) + .and_then(|(hash,)| // match + 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().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(&self, params: Params) -> Result { + fn block_uncles_count_by_hash(&self, params: Params) -> Result { from_params::<(H256,)>(params) - .and_then(|(hash,)| match self.client.block(BlockId::Hash(hash)) { - Some(bytes) => to_value(&BlockView::new(&bytes).uncles_count()), - None => Ok(Value::Null) + .and_then(|(hash,)| + 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)), + _ => take_weak!(self.client).block(block_number.into()) + .map_or(Ok(Value::Null), |bytes| to_value(&U256::from(BlockView::new(&bytes).uncles_count()))) }) } // TODO: do not ignore block number param fn code_at(&self, params: Params) -> Result { from_params::<(Address, BlockNumber)>(params) - .and_then(|(address, _block_number)| to_value(&self.client.code(&address).map_or_else(Bytes::default, Bytes::new))) + .and_then(|(address, _block_number)| + to_value(&take_weak!(self.client).code(&address).map_or_else(Bytes::default, Bytes::new))) } fn block_by_hash(&self, params: Params) -> Result { @@ -197,33 +356,304 @@ impl Eth for EthClient { from_params::<(BlockNumber, Index)>(params) .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(UncleId(BlockId::Hash(hash), index.value()))) + } + + fn uncle_by_block_number_and_index(&self, params: Params) -> Result { + from_params::<(BlockNumber, Index)>(params) + .and_then(|(number, index)| self.uncle(UncleId(number.into(), index.value()))) + } + + fn compilers(&self, params: Params) -> Result { + match params { + Params::None => to_value(&vec![] as &Vec), + _ => Err(Error::invalid_params()) + } + } + + fn logs(&self, params: Params) -> Result { + from_params::<(Filter,)>(params) + .and_then(|(filter,)| { + let logs = take_weak!(self.client).logs(filter.into()) + .into_iter() + .map(From::from) + .collect::>(); + to_value(&logs) + }) + } + + 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(); + match *u { + Some(ref b) => { + let pow_hash = b.hash(); + let target = Ethash::difficulty_to_boundary(b.block().header().difficulty()); + let seed_hash = Ethash::get_seedhash(b.block().header().number()); + to_value(&(pow_hash, seed_hash, target)) + } + _ => Err(Error::internal_error()) + } + }, + _ => Err(Error::invalid_params()) + } + } + + fn submit_work(&self, params: Params) -> Result { + from_params::<(H64, H256, H256)>(params).and_then(|(nonce, pow_hash, mix_hash)| { +// trace!("Decoded: nonce={}, pow_hash={}, mix_hash={}", nonce, pow_hash, mix_hash); + let miner = take_weak!(self.miner); + let client = take_weak!(self.client); + let seal = vec![encode(&mix_hash).to_vec(), encode(&nonce).to_vec()]; + let r = miner.submit_seal(client.deref(), pow_hash, seal); + to_value(&r.is_ok()) + }) + } + + fn submit_hashrate(&self, params: Params) -> Result { + from_params::<(U256, H256)>(params).and_then(|(rate, id)| { + self.external_miner.submit_hashrate(rate, id); + to_value(&true) + }) + } + + fn send_transaction(&self, params: Params) -> Result { + from_params::<(TransactionRequest, )>(params) + .and_then(|(request, )| { + let accounts = take_weak!(self.accounts); + match accounts.account_secret(&request.from) { + Ok(secret) => { + let miner = take_weak!(self.miner); + let client = take_weak!(self.client); + + let transaction = EthTransaction { + nonce: request.nonce.unwrap_or_else(|| client.nonce(&request.from)), + action: request.to.map_or(Action::Create, Action::Call), + gas: request.gas.unwrap_or_else(default_gas), + gas_price: request.gas_price.unwrap_or_else(default_gas_price), + value: request.value.unwrap_or_else(U256::zero), + data: request.data.map_or_else(Vec::new, |d| d.to_vec()) + }; + + let signed_transaction = transaction.sign(&secret); + let hash = signed_transaction.hash(); + + 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); + to_value(&U256::zero()) + } + } + }, + Err(_) => { to_value(&U256::zero()) } + } + }) + } + + fn send_raw_transaction(&self, params: Params) -> Result { + from_params::<(Bytes, )>(params) + .and_then(|(raw_transaction, )| { + let decoded: Result = UntrustedRlp::new(&raw_transaction.to_vec()).as_val(); + match decoded { + Ok(signed_tx) => { + let miner = take_weak!(self.miner); + let client = take_weak!(self.client); + + let hash = signed_tx.hash(); + let import = miner.import_transactions(vec![signed_tx], |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); + to_value(&U256::zero()) + } + } + }, + Err(_) => { to_value(&U256::zero()) } + } + }) + } + + fn call(&self, params: Params) -> Result { + from_params::<(CallRequest, BlockNumber)>(params) + .and_then(|(request, _block_number)| { + let client = take_weak!(self.client); + let accounts = take_weak!(self.accounts); + let signed = Self::sign_call(&client, &accounts, request); + let output = signed.map(|tx| client.call(&tx) + .map(|e| Bytes::new(e.output)) + .unwrap_or(Bytes::default())); + + to_value(&output) + }) + } + + fn estimate_gas(&self, params: Params) -> Result { + from_params::<(CallRequest, BlockNumber)>(params) + .and_then(|(request, _block_number)| { + let client = take_weak!(self.client); + let accounts = take_weak!(self.accounts); + let signed = Self::sign_call(&client, &accounts, request); + let output = signed.map(|tx| client.call(&tx) + .map(|e| e.gas_used + e.refunded) + .unwrap_or(U256::zero())); + + to_value(&output) + }) + } +} /// Eth filter rpc implementation. -pub struct EthFilterClient { - client: Arc +pub struct EthFilterClient + where C: BlockChainClient, + M: MinerService { + + client: Weak, + miner: Weak, + polls: Mutex>, } -impl EthFilterClient { +impl EthFilterClient + where C: BlockChainClient, + M: MinerService { + /// Creates new Eth filter client. - pub fn new(client: Arc) -> Self { + pub fn new(client: &Arc, miner: &Arc) -> Self { EthFilterClient { - client: client + client: Arc::downgrade(client), + miner: Arc::downgrade(miner), + polls: Mutex::new(PollManager::new()), } } } -impl EthFilter for EthFilterClient { - fn new_block_filter(&self, _params: Params) -> Result { - Ok(Value::U64(0)) +impl EthFilter for EthFilterClient + where C: BlockChainClient + 'static, + M: MinerService + 'static { + + fn new_filter(&self, params: Params) -> Result { + from_params::<(Filter,)>(params) + .and_then(|(filter,)| { + let mut polls = self.polls.lock().unwrap(); + let block_number = take_weak!(self.client).chain_info().best_block_number; + let id = polls.create_poll(PollFilter::Logs(block_number, filter.into())); + to_value(&U256::from(id)) + }) } - fn new_pending_transaction_filter(&self, _params: Params) -> Result { - Ok(Value::U64(1)) + fn new_block_filter(&self, params: Params) -> Result { + match params { + Params::None => { + let mut polls = self.polls.lock().unwrap(); + let id = polls.create_poll(PollFilter::Block(take_weak!(self.client).chain_info().best_block_number)); + to_value(&U256::from(id)) + }, + _ => Err(Error::invalid_params()) + } } - fn filter_changes(&self, _: Params) -> Result { - to_value(&self.client.chain_info().best_block_hash).map(|v| Value::Array(vec![v])) + fn new_pending_transaction_filter(&self, params: Params) -> Result { + match params { + Params::None => { + let mut polls = self.polls.lock().unwrap(); + let pending_transactions = take_weak!(self.miner).pending_transactions_hashes(); + let id = polls.create_poll(PollFilter::PendingTransaction(pending_transactions)); + + to_value(&U256::from(id)) + }, + _ => Err(Error::invalid_params()) + } + } + + fn filter_changes(&self, params: Params) -> Result { + let client = take_weak!(self.client); + from_params::<(Index,)>(params) + .and_then(|(index,)| { + let mut polls = self.polls.lock().unwrap(); + match polls.poll_mut(&index.value()) { + None => Ok(Value::Array(vec![] as Vec)), + Some(filter) => match *filter { + PollFilter::Block(ref mut block_number) => { + // + 1, cause we want to return hashes including current block hash. + let current_number = client.chain_info().best_block_number + 1; + let hashes = (*block_number..current_number).into_iter() + .map(BlockId::Number) + .filter_map(|id| client.block_hash(id)) + .collect::>(); + + *block_number = current_number; + + to_value(&hashes) + }, + PollFilter::PendingTransaction(ref mut previous_hashes) => { + let current_hashes = take_weak!(self.miner).pending_transactions_hashes(); + // calculate diff + let previous_hashes_set = previous_hashes.into_iter().map(|h| h.clone()).collect::>(); + let diff = current_hashes + .iter() + .filter(|hash| previous_hashes_set.contains(&hash)) + .cloned() + .collect::>(); + + *previous_hashes = current_hashes; + + to_value(&diff) + }, + PollFilter::Logs(ref mut block_number, ref mut filter) => { + filter.from_block = BlockId::Number(*block_number); + filter.to_block = BlockId::Latest; + let logs = client.logs(filter.clone()) + .into_iter() + .map(From::from) + .collect::>(); + + let current_number = client.chain_info().best_block_number; + + *block_number = current_number; + to_value(&logs) + } + } + } + }) + } + + fn uninstall_filter(&self, params: Params) -> Result { + from_params::<(Index,)>(params) + .and_then(|(index,)| { + self.polls.lock().unwrap().remove_poll(&index.value()); + to_value(&true) + }) } } diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs index bc8b436fd..10d451e9f 100644 --- a/rpc/src/v1/impls/mod.rs +++ b/rpc/src/v1/impls/mod.rs @@ -15,10 +15,22 @@ // along with Parity. If not, see . //! Ethereum rpc interface implementation. + +macro_rules! take_weak { + ($weak: expr) => { + match $weak.upgrade() { + Some(arc) => arc, + None => return Err(Error::internal_error()) + } + } +} + mod web3; mod eth; mod net; +mod personal; pub use self::web3::Web3Client; pub use self::eth::{EthClient, EthFilterClient}; pub use self::net::NetClient; +pub use self::personal::PersonalClient; diff --git a/rpc/src/v1/impls/net.rs b/rpc/src/v1/impls/net.rs index b36042dba..e52fc0bd4 100644 --- a/rpc/src/v1/impls/net.rs +++ b/rpc/src/v1/impls/net.rs @@ -15,31 +15,36 @@ // along with Parity. If not, see . //! Net rpc implementation. -use std::sync::Arc; +use std::sync::{Arc, Weak}; use jsonrpc_core::*; -use ethsync::EthSync; +use ethsync::SyncProvider; use v1::traits::Net; /// Net rpc implementation. -pub struct NetClient { - sync: Arc +pub struct NetClient where S: SyncProvider { + sync: Weak } -impl NetClient { +impl NetClient where S: SyncProvider { /// Creates new NetClient. - pub fn new(sync: Arc) -> Self { + pub fn new(sync: &Arc) -> Self { NetClient { - sync: sync + sync: Arc::downgrade(sync) } } } -impl Net for NetClient { +impl Net for NetClient where S: SyncProvider + 'static { fn version(&self, _: Params) -> Result { - Ok(Value::U64(self.sync.status().protocol_version as u64)) + Ok(Value::String(format!("{}", take_weak!(self.sync).status().protocol_version).to_owned())) } fn peer_count(&self, _params: Params) -> Result { - Ok(Value::U64(self.sync.status().num_peers as u64)) + Ok(Value::String(format!("0x{:x}", take_weak!(self.sync).status().num_peers as u64).to_owned())) + } + + fn is_listening(&self, _: Params) -> Result { + // right now (11 march 2016), we are always listening for incoming connections + Ok(Value::Bool(true)) } } diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs new file mode 100644 index 000000000..2822059d6 --- /dev/null +++ b/rpc/src/v1/impls/personal.rs @@ -0,0 +1,69 @@ +// 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 . + +//! Account management (personal) rpc implementation +use std::sync::{Arc, Weak}; +use jsonrpc_core::*; +use v1::traits::Personal; +use util::keys::store::*; +use util::Address; + +/// Account management (personal) rpc implementation. +pub struct PersonalClient where A: AccountProvider { + accounts: Weak, +} + +impl PersonalClient where A: AccountProvider { + /// Creates new PersonalClient + pub fn new(store: &Arc) -> Self { + PersonalClient { + accounts: Arc::downgrade(store), + } + } +} + +impl Personal for PersonalClient where A: AccountProvider + 'static { + fn accounts(&self, _: Params) -> Result { + let store = take_weak!(self.accounts); + match store.accounts() { + Ok(account_list) => to_value(&account_list), + Err(_) => Err(Error::internal_error()) + } + } + + fn new_account(&self, params: Params) -> Result { + from_params::<(String, )>(params).and_then( + |(pass, )| { + let store = take_weak!(self.accounts); + match store.new_account(&pass) { + Ok(address) => Ok(Value::String(format!("0x{:?}", address))), + Err(_) => Err(Error::internal_error()) + } + } + ) + } + + fn unlock_account(&self, params: Params) -> Result { + from_params::<(Address, String, u64)>(params).and_then( + |(account, account_pass, _)|{ + let store = take_weak!(self.accounts); + match store.unlock_account(&account, &account_pass) { + Ok(_) => Ok(Value::Bool(true)), + Err(_) => Ok(Value::Bool(false)), + } + }) + } +} diff --git a/rpc/src/v1/impls/web3.rs b/rpc/src/v1/impls/web3.rs index f10150a30..64a82adb9 100644 --- a/rpc/src/v1/impls/web3.rs +++ b/rpc/src/v1/impls/web3.rs @@ -15,8 +15,8 @@ // along with Parity. If not, see . //! Web3 rpc implementation. -use target_info::Target; use jsonrpc_core::*; +use util::version; use v1::traits::Web3; /// Web3 rpc implementation. @@ -30,7 +30,7 @@ impl Web3Client { impl Web3 for Web3Client { fn client_version(&self, params: Params) -> Result { match params { - Params::None => Ok(Value::String(format!("Parity/-/{}/{}-{}-{}/rust1.8-nightly", env!("CARGO_PKG_VERSION"), Target::arch(), Target::env(), Target::os()))), + Params::None => Ok(Value::String(version().to_owned().replace("Parity/", "Parity//"))), _ => Err(Error::invalid_params()) } } diff --git a/rpc/src/v1/mod.rs b/rpc/src/v1/mod.rs index 01635e872..c81f58156 100644 --- a/rpc/src/v1/mod.rs +++ b/rpc/src/v1/mod.rs @@ -15,14 +15,15 @@ // along with Parity. If not, see . //! Ethcore rpc v1. -//! +//! //! Compliant with ethereum rpc. pub mod traits; mod impls; mod types; -#[cfg(test)] -mod tests; +mod helpers; -pub use self::traits::{Web3, Eth, EthFilter, Net}; +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 new file mode 100644 index 000000000..4564076eb --- /dev/null +++ b/rpc/src/v1/tests/eth.rs @@ -0,0 +1,498 @@ +// 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 std::str::FromStr; +use std::collections::HashMap; +use std::sync::{Arc, RwLock}; +use jsonrpc_core::IoHandler; +use util::hash::{Address, H256, FixedHash}; +use util::numbers::{Uint, U256}; +use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed, TransactionId}; +use ethcore::log_entry::{LocalizedLogEntry, LogEntry}; +use ethcore::receipt::LocalizedReceipt; +use v1::{Eth, EthClient}; +use v1::tests::helpers::{TestAccount, TestAccountProvider, TestSyncProvider, Config, TestMinerService, TestExternalMiner}; + +fn blockchain_client() -> Arc { + let client = TestBlockChainClient::new(); + Arc::new(client) +} + +fn accounts_provider() -> Arc { + let mut accounts = HashMap::new(); + accounts.insert(Address::from(1), TestAccount::new("test")); + let ap = TestAccountProvider::new(accounts); + Arc::new(ap) +} + +fn sync_provider() -> Arc { + Arc::new(TestSyncProvider::new(Config { + protocol_version: 65, + num_peers: 120, + })) +} + +fn miner_service() -> Arc { + Arc::new(TestMinerService::default()) +} + +struct EthTester { + pub client: Arc, + pub sync: Arc, + _accounts_provider: Arc, + _miner: Arc, + hashrates: Arc>>, + pub io: IoHandler, +} + +impl Default for EthTester { + fn default() -> Self { + let client = blockchain_client(); + let sync = sync_provider(); + let ap = accounts_provider(); + let miner = miner_service(); + let hashrates = Arc::new(RwLock::new(HashMap::new())); + let external_miner = TestExternalMiner::new(hashrates.clone()); + let eth = EthClient::new_with_external_miner(&client, &sync, &ap, &miner, external_miner).to_delegate(); + let io = IoHandler::new(); + io.add_delegate(eth); + EthTester { + client: client, + sync: sync, + _accounts_provider: ap, + _miner: miner, + io: io, + hashrates: hashrates, + } + } +} + +#[test] +fn rpc_eth_protocol_version() { + let request = r#"{"jsonrpc": "2.0", "method": "eth_protocolVersion", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"65","id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + +#[test] +#[ignore] +fn rpc_eth_syncing() { + unimplemented!() +} + +#[test] +fn rpc_eth_hashrate() { + let tester = EthTester::default(); + tester.hashrates.write().unwrap().insert(H256::from(0), U256::from(0xfffa)); + tester.hashrates.write().unwrap().insert(H256::from(0), U256::from(0xfffb)); + tester.hashrates.write().unwrap().insert(H256::from(1), U256::from(0x1)); + + let request = r#"{"jsonrpc": "2.0", "method": "eth_hashrate", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"0xfffc","id":1}"#; + + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_submit_hashrate() { + let tester = EthTester::default(); + + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_submitHashrate", + "params": [ + "0x0000000000000000000000000000000000000000000000000000000000500000", + "0x59daa26581d0acd1fce254fb7e85952f4c09d0915afd33d3886cd914bc7d283c"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; + + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); + assert_eq!(tester.hashrates.read().unwrap().get(&H256::from("0x59daa26581d0acd1fce254fb7e85952f4c09d0915afd33d3886cd914bc7d283c")).cloned(), + Some(U256::from(0x500_000))); +} + +#[test] +#[ignore] +fn rpc_eth_author() { + unimplemented!() +} + +#[test] +fn rpc_eth_mining() { + let tester = EthTester::default(); + + let request = r#"{"jsonrpc": "2.0", "method": "eth_mining", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); + + tester.hashrates.write().unwrap().insert(H256::from(1), U256::from(0x1)); + + let request = r#"{"jsonrpc": "2.0", "method": "eth_mining", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_gas_price() { + let request = r#"{"jsonrpc": "2.0", "method": "eth_gasPrice", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"0x0ba43b7400","id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_accounts() { + let request = r#"{"jsonrpc": "2.0", "method": "eth_accounts", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":["0x0000000000000000000000000000000000000001"],"id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_block_number() { + let tester = EthTester::default(); + tester.client.add_blocks(10, EachBlockWith::Nothing); + + let request = r#"{"jsonrpc": "2.0", "method": "eth_blockNumber", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"0x0a","id":1}"#; + + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_balance() { + let tester = EthTester::default(); + tester.client.set_balance(Address::from(1), U256::from(5)); + + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getBalance", + "params": ["0x0000000000000000000000000000000000000001", "latest"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0x05","id":1}"#; + + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_storage_at() { + let tester = EthTester::default(); + tester.client.set_storage(Address::from(1), H256::from(4), H256::from(7)); + + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getStorageAt", + "params": ["0x0000000000000000000000000000000000000001", "0x4", "latest"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0x07","id":1}"#; + + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_transaction_count() { + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getTransactionCount", + "params": ["0x0000000000000000000000000000000000000001", "latest"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0x00","id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_block_transaction_count_by_hash() { + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getBlockTransactionCountByHash", + "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":null,"id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_transaction_count_by_number() { + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getBlockTransactionCountByNumber", + "params": ["latest"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0x00","id":1}"#; + + 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#"{ + "jsonrpc": "2.0", + "method": "eth_getUncleCountByBlockHash", + "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":null,"id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_uncle_count_by_block_number() { + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getUncleCountByBlockNumber", + "params": ["latest"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0x00","id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_code() { + let tester = EthTester::default(); + tester.client.set_code(Address::from(1), vec![0xff, 0x21]); + + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getCode", + "params": ["0x0000000000000000000000000000000000000001", "latest"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0xff21","id":1}"#; + + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_call() { + 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], + trace: None, + }); + + 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], + trace: None, + }); + + 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] +#[ignore] +fn rpc_eth_send_transaction() { + unimplemented!() +} + +#[test] +#[ignore] +fn rpc_eth_send_raw_transaction() { + unimplemented!() +} + +#[test] +#[ignore] +fn rpc_eth_sign() { + unimplemented!() +} + +#[test] +fn rpc_eth_transaction_receipt() { + let receipt = LocalizedReceipt { + transaction_hash: H256::zero(), + transaction_index: 0, + block_hash: H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap(), + block_number: 0x4510c, + cumulative_gas_used: U256::from(0x20), + gas_used: U256::from(0x10), + contract_address: None, + logs: vec![LocalizedLogEntry { + entry: LogEntry { + address: Address::from_str("33990122638b9132ca29c723bdf037f1a891a70c").unwrap(), + topics: vec![ + H256::from_str("a6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc").unwrap(), + H256::from_str("4861736852656700000000000000000000000000000000000000000000000000").unwrap() + ], + data: vec![], + }, + block_hash: H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap(), + block_number: 0x4510c, + transaction_hash: H256::new(), + transaction_index: 0, + log_index: 1, + }] + }; + + let hash = H256::from_str("b903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238").unwrap(); + let tester = EthTester::default(); + tester.client.set_transaction_receipt(TransactionId::Hash(hash), receipt); + + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getTransactionReceipt", + "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":{"blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x04510c","contractAddress":null,"cumulativeGasUsed":"0x20","gasUsed":"0x10","logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x04510c","data":"0x","logIndex":"0x01","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x00"}],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x00"},"id":1}"#; + + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_transaction_receipt_null() { + let tester = EthTester::default(); + + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getTransactionReceipt", + "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":null,"id":1}"#; + + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_compilers() { + let request = r#"{"jsonrpc": "2.0", "method": "eth_getCompilers", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":[],"id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_compile_lll() { + let request = r#"{"jsonrpc": "2.0", "method": "eth_compileLLL", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","error":{"code":-32603,"message":"Internal error","data":null},"id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_compile_solidity() { + let request = r#"{"jsonrpc": "2.0", "method": "eth_compileSolidity", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","error":{"code":-32603,"message":"Internal error","data":null},"id":1}"#; + + assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_compile_serpent() { + let request = r#"{"jsonrpc": "2.0", "method": "eth_compileSerpent", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","error":{"code":-32603,"message":"Internal error","data":null},"id":1}"#; + + 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 new file mode 100644 index 000000000..6ef6e2b59 --- /dev/null +++ b/rpc/src/v1/tests/helpers/account_provider.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 . + +//! Test implementation of account provider. + +use std::sync::RwLock; +use std::collections::HashMap; +use std::io; +use util::hash::{Address, H256, FixedHash}; +use util::crypto::{Secret, Signature}; +use util::keys::store::{AccountProvider, SigningError, EncryptedHashMapError}; + +/// Account mock. +#[derive(Clone)] +pub struct TestAccount { + /// True if account is unlocked. + pub unlocked: bool, + /// Account's password. + pub password: String, +} + +impl TestAccount { + /// Creates new test account. + pub fn new(password: &str) -> Self { + TestAccount { + unlocked: false, + password: password.to_owned(), + } + } +} + +/// Test account provider. +pub struct TestAccountProvider { + accounts: RwLock>, + /// Added accounts passwords. + pub adds: RwLock>, +} + +impl TestAccountProvider { + /// Basic constructor. + pub fn new(accounts: HashMap) -> Self { + TestAccountProvider { + accounts: RwLock::new(accounts), + adds: RwLock::new(vec![]), + } + } +} + +impl AccountProvider for TestAccountProvider { + fn accounts(&self) -> Result, io::Error> { + Ok(self.accounts.read().unwrap().keys().cloned().collect()) + } + + fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError> { + match self.accounts.write().unwrap().get_mut(account) { + Some(ref mut acc) if acc.password == pass => { + acc.unlocked = true; + Ok(()) + }, + Some(_) => Err(EncryptedHashMapError::InvalidPassword), + None => Err(EncryptedHashMapError::UnknownIdentifier), + } + } + + fn new_account(&self, pass: &str) -> Result { + let mut adds = self.adds.write().unwrap(); + let address = Address::from(adds.len() as u64 + 2); + adds.push(pass.to_owned()); + Ok(address) + } + + fn account_secret(&self, _account: &Address) -> Result { + Ok(Secret::random()) + } + + fn sign(&self, _account: &Address, _message: &H256) -> Result { + unimplemented!() + } + +} + diff --git a/rpc/src/v1/tests/helpers/external_miner.rs b/rpc/src/v1/tests/helpers/external_miner.rs new file mode 100644 index 000000000..1799c36c5 --- /dev/null +++ b/rpc/src/v1/tests/helpers/external_miner.rs @@ -0,0 +1,50 @@ +// 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 std::collections::HashMap; +use std::sync::{Arc, RwLock}; +use util::numbers::U256; +use util::hash::H256; +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, + } + } +} + +impl ExternalMinerService for TestExternalMiner { + fn submit_hashrate(&self, hashrate: U256, id: H256) { + self.hashrates.write().unwrap().insert(id, hashrate); + } + + fn hashrate(&self) -> U256 { + self.hashrates.read().unwrap().iter().fold(U256::from(0), |sum, (_, v)| sum + *v) + } + + fn is_mining(&self) -> bool { + !self.hashrates.read().unwrap().is_empty() + } +} diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs new file mode 100644 index 000000000..7f07341bf --- /dev/null +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -0,0 +1,79 @@ +// 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 . + +//! 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, AccountDetails}; + +/// 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 { + 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_account: T) -> Vec> + where T: Fn(&Address) -> AccountDetails { unimplemented!(); } + + /// Returns hashes of transactions currently in pending + 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!(); } + + /// Called when blocks are imported to chain, updates transactions queue. + fn chain_new_blocks(&self, _chain: &BlockChainClient, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) { unimplemented!(); } + + /// New chain head event. Restart mining operation. + 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> { + &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!(); } +} diff --git a/rpc/src/v1/tests/helpers/mod.rs b/rpc/src/v1/tests/helpers/mod.rs new file mode 100644 index 000000000..c9db61f6d --- /dev/null +++ b/rpc/src/v1/tests/helpers/mod.rs @@ -0,0 +1,27 @@ +// 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 . + +//! Test rpc services. + +mod account_provider; +mod sync_provider; +mod miner_service; +mod external_miner; + +pub use self::account_provider::{TestAccount, TestAccountProvider}; +pub use self::sync_provider::{Config, TestSyncProvider}; +pub use self::miner_service::{TestMinerService}; +pub use self::external_miner::TestExternalMiner; diff --git a/rpc/src/v1/tests/helpers/sync_provider.rs b/rpc/src/v1/tests/helpers/sync_provider.rs new file mode 100644 index 000000000..48b4f55a9 --- /dev/null +++ b/rpc/src/v1/tests/helpers/sync_provider.rs @@ -0,0 +1,61 @@ +// 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 . + +//! 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 { + /// Sync status. + pub status: RwLock, +} + +impl TestSyncProvider { + /// Creates new sync provider. + pub fn new(config: Config) -> Self { + TestSyncProvider { + status: RwLock::new(SyncStatus { + state: SyncState::NotSynced, + protocol_version: config.protocol_version, + start_block_number: 0, + last_imported_block_number: None, + highest_block_number: None, + blocks_total: 0, + blocks_received: 0, + num_peers: config.num_peers, + num_active_peers: 0, + mem_used: 0, + }), + } + } +} + +impl SyncProvider for TestSyncProvider { + fn status(&self) -> SyncStatus { + self.status.read().unwrap().clone() + } +} + diff --git a/rpc/src/v1/tests/mod.rs b/rpc/src/v1/tests/mod.rs index bdf4567b6..7a6340ce1 100644 --- a/rpc/src/v1/tests/mod.rs +++ b/rpc/src/v1/tests/mod.rs @@ -1 +1,27 @@ -//TODO: load custom blockchain state and test +// 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 . + +//!TODO: load custom blockchain state and test + +pub mod helpers; +#[cfg(test)] +mod eth; +#[cfg(test)] +mod net; +#[cfg(test)] +mod web3; +#[cfg(test)] +mod personal; diff --git a/rpc/src/v1/tests/net.rs b/rpc/src/v1/tests/net.rs new file mode 100644 index 000000000..e24045ca6 --- /dev/null +++ b/rpc/src/v1/tests/net.rs @@ -0,0 +1,66 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::sync::Arc; +use jsonrpc_core::IoHandler; +use v1::{Net, NetClient}; +use v1::tests::helpers::{Config, TestSyncProvider}; + +fn sync_provider() -> Arc { + Arc::new(TestSyncProvider::new(Config { + protocol_version: 65, + num_peers: 120, + })) +} + +#[test] +fn rpc_net_version() { + let sync = sync_provider(); + let net = NetClient::new(&sync).to_delegate(); + let io = IoHandler::new(); + io.add_delegate(net); + + let request = r#"{"jsonrpc": "2.0", "method": "net_version", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"65","id":1}"#; + + assert_eq!(io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_net_peer_count() { + let sync = sync_provider(); + let net = NetClient::new(&sync).to_delegate(); + let io = IoHandler::new(); + io.add_delegate(net); + + let request = r#"{"jsonrpc": "2.0", "method": "net_peerCount", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"0x78","id":1}"#; + + assert_eq!(io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_net_listening() { + let sync = sync_provider(); + let net = NetClient::new(&sync).to_delegate(); + let io = IoHandler::new(); + io.add_delegate(net); + + let request = r#"{"jsonrpc": "2.0", "method": "net_listening", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; + + assert_eq!(io.handle_request(request), Some(response.to_owned())); +} diff --git a/rpc/src/v1/tests/personal.rs b/rpc/src/v1/tests/personal.rs new file mode 100644 index 000000000..261527c47 --- /dev/null +++ b/rpc/src/v1/tests/personal.rs @@ -0,0 +1,59 @@ +// 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 std::sync::Arc; +use jsonrpc_core::IoHandler; +use v1::tests::helpers::{TestAccount, TestAccountProvider}; +use v1::{PersonalClient, Personal}; +use util::numbers::*; +use std::collections::*; + +fn accounts_provider() -> Arc { + let mut accounts = HashMap::new(); + accounts.insert(Address::from(1), TestAccount::new("test")); + let ap = TestAccountProvider::new(accounts); + Arc::new(ap) +} + +fn setup() -> (Arc, IoHandler) { + let test_provider = accounts_provider(); + let personal = PersonalClient::new(&test_provider); + let io = IoHandler::new(); + io.add_delegate(personal.to_delegate()); + (test_provider, io) +} + +#[test] +fn accounts() { + let (_test_provider, io) = setup(); + + let request = r#"{"jsonrpc": "2.0", "method": "personal_listAccounts", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":["0x0000000000000000000000000000000000000001"],"id":1}"#; + + assert_eq!(io.handle_request(request), Some(response.to_owned())); +} + + +#[test] +fn new_account() { + let (_test_provider, io) = setup(); + + let request = r#"{"jsonrpc": "2.0", "method": "personal_newAccount", "params": ["pass"], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"0x0000000000000000000000000000000000000002","id":1}"#; + + assert_eq!(io.handle_request(request), Some(response.to_owned())); +} + diff --git a/rpc/src/v1/tests/web3.rs b/rpc/src/v1/tests/web3.rs new file mode 100644 index 000000000..c717d361a --- /dev/null +++ b/rpc/src/v1/tests/web3.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 . + +use jsonrpc_core::IoHandler; +use util::version; +use v1::{Web3, Web3Client}; + +#[test] +fn rpc_web3_version() { + let web3 = Web3Client::new().to_delegate(); + let io = IoHandler::new(); + io.add_delegate(web3); + + let v = version().to_owned().replace("Parity/", "Parity//"); + + let request = r#"{"jsonrpc": "2.0", "method": "web3_clientVersion", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"VER","id":1}"#.to_owned().replace("VER", v.as_ref()); + + assert_eq!(io.handle_request(request), Some(response)); +} diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index d2aeb0f9e..8a48e0dfe 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -55,22 +55,34 @@ pub trait Eth: Sized + Send + Sync + 'static { /// Returns block with given number. fn block_by_number(&self, _: Params) -> Result { rpc_unimplemented!() } - + /// Returns the number of transactions sent from given address at given time (block number). fn transaction_count(&self, _: Params) -> Result { rpc_unimplemented!() } - /// Returns the number of transactions in a block. - fn block_transaction_count(&self, _: Params) -> Result { rpc_unimplemented!() } + /// Returns the number of transactions in a block with given hash. + fn block_transaction_count_by_hash(&self, _: Params) -> Result { rpc_unimplemented!() } - /// Returns the number of uncles in a given block. - fn block_uncles_count(&self, _: Params) -> Result { rpc_unimplemented!() } + /// Returns the number of transactions in a block with given block number. + fn block_transaction_count_by_number(&self, _: Params) -> Result { rpc_unimplemented!() } + + /// Returns the number of uncles in a block with given hash. + fn block_uncles_count_by_hash(&self, _: Params) -> Result { rpc_unimplemented!() } + + /// Returns the number of uncles in a block with given block number. + fn block_uncles_count_by_number(&self, _: Params) -> Result { rpc_unimplemented!() } /// Returns the code at given address at given time (block number). fn code_at(&self, _: Params) -> Result { rpc_unimplemented!() } + /// Signs the data with given address signature. + fn sign(&self, _: Params) -> Result { rpc_unimplemented!() } + /// Sends transaction. fn send_transaction(&self, _: Params) -> Result { rpc_unimplemented!() } + /// Sends signed transaction. + fn send_raw_transaction(&self, _: Params) -> Result { rpc_unimplemented!() } + /// Call contract. fn call(&self, _: Params) -> Result { rpc_unimplemented!() } @@ -90,7 +102,10 @@ pub trait Eth: Sized + Send + Sync + 'static { fn transaction_receipt(&self, _: Params) -> Result { rpc_unimplemented!() } /// Returns an uncles at given block and index. - fn uncle_at(&self, _: Params) -> Result { rpc_unimplemented!() } + fn uncle_by_block_hash_and_index(&self, _: Params) -> Result { rpc_unimplemented!() } + + /// Returns an uncles at given block and index. + fn uncle_by_block_number_and_index(&self, _: Params) -> Result { rpc_unimplemented!() } /// Returns available compilers. fn compilers(&self, _: Params) -> Result { rpc_unimplemented!() } @@ -127,15 +142,17 @@ pub trait Eth: Sized + Send + Sync + 'static { delegate.add_method("eth_gasPrice", Eth::gas_price); delegate.add_method("eth_accounts", Eth::accounts); delegate.add_method("eth_blockNumber", Eth::block_number); - delegate.add_method("eth_balance", Eth::balance); + delegate.add_method("eth_getBalance", Eth::balance); delegate.add_method("eth_getStorageAt", Eth::storage_at); delegate.add_method("eth_getTransactionCount", Eth::transaction_count); - delegate.add_method("eth_getBlockTransactionCountByHash", Eth::block_transaction_count); - delegate.add_method("eth_getBlockTransactionCountByNumber", Eth::block_transaction_count); - delegate.add_method("eth_getUncleCountByBlockHash", Eth::block_uncles_count); - delegate.add_method("eth_getUncleCountByBlockNumber", Eth::block_uncles_count); - delegate.add_method("eth_code", Eth::code_at); + delegate.add_method("eth_getBlockTransactionCountByHash", Eth::block_transaction_count_by_hash); + delegate.add_method("eth_getBlockTransactionCountByNumber", Eth::block_transaction_count_by_number); + delegate.add_method("eth_getUncleCountByBlockHash", Eth::block_uncles_count_by_hash); + delegate.add_method("eth_getUncleCountByBlockNumber", Eth::block_uncles_count_by_number); + delegate.add_method("eth_getCode", Eth::code_at); + delegate.add_method("eth_sign", Eth::sign); delegate.add_method("eth_sendTransaction", Eth::send_transaction); + delegate.add_method("eth_sendRawTransaction", Eth::send_raw_transaction); delegate.add_method("eth_call", Eth::call); delegate.add_method("eth_estimateGas", Eth::estimate_gas); delegate.add_method("eth_getBlockByHash", Eth::block_by_hash); @@ -144,8 +161,8 @@ pub trait Eth: Sized + Send + Sync + 'static { delegate.add_method("eth_getTransactionByBlockHashAndIndex", Eth::transaction_by_block_hash_and_index); delegate.add_method("eth_getTransactionByBlockNumberAndIndex", Eth::transaction_by_block_number_and_index); delegate.add_method("eth_getTransactionReceipt", Eth::transaction_receipt); - delegate.add_method("eth_getUncleByBlockHashAndIndex", Eth::uncle_at); - delegate.add_method("eth_getUncleByBlockNumberAndIndex", Eth::uncle_at); + delegate.add_method("eth_getUncleByBlockHashAndIndex", Eth::uncle_by_block_hash_and_index); + delegate.add_method("eth_getUncleByBlockNumberAndIndex", Eth::uncle_by_block_number_and_index); delegate.add_method("eth_getCompilers", Eth::compilers); delegate.add_method("eth_compileLLL", Eth::compile_lll); delegate.add_method("eth_compileSolidity", Eth::compile_solidity); diff --git a/rpc/src/v1/traits/mod.rs b/rpc/src/v1/traits/mod.rs index c9af6dac3..0a95cb050 100644 --- a/rpc/src/v1/traits/mod.rs +++ b/rpc/src/v1/traits/mod.rs @@ -23,7 +23,9 @@ macro_rules! rpc_unimplemented { pub mod web3; pub mod eth; pub mod net; +pub mod personal; pub use self::web3::Web3; pub use self::eth::{Eth, EthFilter}; pub use self::net::Net; +pub use self::personal::Personal; diff --git a/rpc/src/v1/traits/personal.rs b/rpc/src/v1/traits/personal.rs new file mode 100644 index 000000000..0cf72951c --- /dev/null +++ b/rpc/src/v1/traits/personal.rs @@ -0,0 +1,41 @@ +// 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 . + +//! Personal rpc interface. +use std::sync::Arc; +use jsonrpc_core::*; + +/// Personal rpc interface. +pub trait Personal: Sized + Send + Sync + 'static { + + /// Lists all stored accounts + fn accounts(&self, _: Params) -> Result { rpc_unimplemented!() } + + /// Creates new account (it becomes new current unlocked account) + fn new_account(&self, _: Params) -> Result { rpc_unimplemented!() } + + /// Unlocks specified account for use (can only be one unlocked account at one moment) + fn unlock_account(&self, _: Params) -> Result { rpc_unimplemented!() } + + /// Should be used to convert object to io delegate. + fn to_delegate(self) -> IoDelegate { + let mut delegate = IoDelegate::new(Arc::new(self)); + delegate.add_method("personal_listAccounts", Personal::accounts); + delegate.add_method("personal_newAccount", Personal::new_account); + delegate.add_method("personal_unlockAccount", Personal::unlock_account); + delegate + } +} diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index b92111bcb..ac334dd2b 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -15,8 +15,7 @@ // along with Parity. If not, see . use serde::{Serialize, Serializer}; -use util::hash::*; -use util::uint::*; +use util::numbers::*; use v1::types::{Bytes, Transaction, OptionalValue}; #[derive(Debug)] @@ -64,15 +63,15 @@ 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 } #[cfg(test)] mod tests { use serde_json; - use util::hash::*; - use util::uint::*; + use util::numbers::*; use v1::types::{Transaction, Bytes, OptionalValue}; use super::*; @@ -80,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(); @@ -106,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/block_number.rs b/rpc/src/v1/types/block_number.rs index 546816eba..c955ec895 100644 --- a/rpc/src/v1/types/block_number.rs +++ b/rpc/src/v1/types/block_number.rs @@ -30,7 +30,7 @@ pub enum BlockNumber { impl Deserialize for BlockNumber { fn deserialize(deserializer: &mut D) -> Result where D: Deserializer { - deserializer.visit(BlockNumberVisitor) + deserializer.deserialize(BlockNumberVisitor) } } @@ -44,8 +44,8 @@ impl Visitor for BlockNumberVisitor { "latest" => Ok(BlockNumber::Latest), "earliest" => Ok(BlockNumber::Earliest), "pending" => Ok(BlockNumber::Pending), - _ if value.starts_with("0x") => u64::from_str_radix(&value[2..], 16).map(BlockNumber::Num).map_err(|_| Error::syntax("invalid block number")), - _ => value.parse::().map(BlockNumber::Num).map_err(|_| Error::syntax("invalid block number")) + _ if value.starts_with("0x") => u64::from_str_radix(&value[2..], 16).map(BlockNumber::Num).map_err(|_| Error::custom("invalid block number")), + _ => value.parse::().map(BlockNumber::Num).map_err(|_| Error::custom("invalid block number")) } } @@ -55,13 +55,12 @@ impl Visitor for BlockNumberVisitor { } impl Into for BlockNumber { - #[allow(match_same_arms)] fn into(self) -> BlockId { match self { BlockNumber::Num(n) => BlockId::Number(n), BlockNumber::Earliest => BlockId::Earliest, - BlockNumber::Latest => BlockId::Latest, - BlockNumber::Pending => BlockId::Latest // TODO: change this once blockid support pending + // TODO: change this once blockid support pendingst, + BlockNumber::Pending | BlockNumber::Latest => BlockId::Latest, } } } diff --git a/rpc/src/v1/types/bytes.rs b/rpc/src/v1/types/bytes.rs index d6a648d7c..8c47806f8 100644 --- a/rpc/src/v1/types/bytes.rs +++ b/rpc/src/v1/types/bytes.rs @@ -15,10 +15,12 @@ // along with Parity. If not, see . use rustc_serialize::hex::ToHex; -use serde::{Serialize, Serializer}; +use serde::{Serialize, Serializer, Deserialize, Deserializer, Error}; +use serde::de::Visitor; +use util::common::FromHex; /// Wrapper structure around vector of bytes. -#[derive(Debug)] +#[derive(Debug, PartialEq, Default)] pub struct Bytes(Vec); impl Bytes { @@ -26,24 +28,44 @@ impl Bytes { pub fn new(bytes: Vec) -> Bytes { Bytes(bytes) } -} - -impl Default for Bytes { - fn default() -> Self { - // default serialized value is 0x00 - Bytes(vec![0]) - } + pub fn to_vec(self) -> Vec { let Bytes(x) = self; x } } impl Serialize for Bytes { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { let mut serialized = "0x".to_owned(); serialized.push_str(self.0.to_hex().as_ref()); - serializer.visit_str(serialized.as_ref()) + serializer.serialize_str(serialized.as_ref()) } } +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 { + if value.len() >= 2 && &value[0..2] == "0x" { + Ok(Bytes::new(FromHex::from_hex(&value[2..]).unwrap_or_else(|_| vec![]))) + } else { + Err(Error::custom("invalid hex")) + } + } + + fn visit_string(&mut self, value: String) -> Result where E: Error { + self.visit_str(value.as_ref()) + } +} + + #[cfg(test)] mod tests { use super::*; diff --git a/rpc/src/v1/types/call_request.rs b/rpc/src/v1/types/call_request.rs new file mode 100644 index 000000000..a47d40eb3 --- /dev/null +++ b/rpc/src/v1/types/call_request.rs @@ -0,0 +1,106 @@ +// 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::hash::Address; +use util::numbers::U256; +use v1::types::Bytes; + +#[derive(Debug, Default, PartialEq, Deserialize)] +pub struct CallRequest { + pub from: Option
, + pub to: Option
, + #[serde(rename="gasPrice")] + pub gas_price: Option, + pub gas: Option, + pub value: Option, + pub data: Option, + pub nonce: Option, +} + +#[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; + use ethcore::transaction::{Transaction, Action}; + use v1::types::Bytes; + use super::*; + + #[test] + fn transaction_request_deserialize() { + let s = r#"{ + "from":"0x0000000000000000000000000000000000000001", + "to":"0x0000000000000000000000000000000000000002", + "gasPrice":"0x1", + "gas":"0x2", + "value":"0x3", + "data":"0x123456", + "nonce":"0x4" + }"#; + let deserialized: CallRequest = serde_json::from_str(s).unwrap(); + + assert_eq!(deserialized, CallRequest { + from: Some(Address::from(1)), + to: Some(Address::from(2)), + gas_price: Some(U256::from(1)), + gas: Some(U256::from(2)), + value: Some(U256::from(3)), + data: Some(Bytes::new(vec![0x12, 0x34, 0x56])), + nonce: Some(U256::from(4)), + }); + } + + #[test] + fn transaction_request_deserialize2() { + let s = r#"{ + "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "value": "0x9184e72a", + "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" + }"#; + let deserialized: CallRequest = serde_json::from_str(s).unwrap(); + + assert_eq!(deserialized, CallRequest { + from: Some(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"}"#; + let deserialized: CallRequest = serde_json::from_str(s).unwrap(); + + assert_eq!(deserialized, CallRequest { + from: Some(Address::from(1)), + to: None, + gas_price: None, + gas: None, + value: None, + data: None, + nonce: None, + }); + } +} diff --git a/rpc/src/v1/types/filter.rs b/rpc/src/v1/types/filter.rs index 9b21cf8e7..16a08764b 100644 --- a/rpc/src/v1/types/filter.rs +++ b/rpc/src/v1/types/filter.rs @@ -17,39 +17,67 @@ use serde::{Deserialize, Deserializer, Error}; use serde_json::value; use jsonrpc_core::Value; -use util::hash::*; +use util::numbers::*; use v1::types::BlockNumber; +use ethcore::filter::Filter as EthFilter; +use ethcore::client::BlockId; #[derive(Debug, PartialEq)] -pub enum Topic { - Single(H256), - Multiple(Vec), - Null +pub enum VariadicValue where T: Deserialize { + Single(T), + Multiple(Vec), + Null, } -impl Deserialize for Topic { - fn deserialize(deserializer: &mut D) -> Result +impl Deserialize for VariadicValue where T: Deserialize { + fn deserialize(deserializer: &mut D) -> Result, D::Error> where D: Deserializer { let v = try!(Value::deserialize(deserializer)); if v.is_null() { - return Ok(Topic::Null); + return Ok(VariadicValue::Null); } - Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(Topic::Single) - .or_else(|_| Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(Topic::Multiple)) - .map_err(|_| Error::syntax("")) // unreachable, but types must match + Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(VariadicValue::Single) + .or_else(|_| Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(VariadicValue::Multiple)) + .map_err(|_| Error::custom("")) // unreachable, but types must match } } +pub type FilterAddress = VariadicValue
; +pub type Topic = VariadicValue; + #[derive(Debug, PartialEq, Deserialize)] +#[serde(deny_unknown_fields)] pub struct Filter { #[serde(rename="fromBlock")] pub from_block: Option, #[serde(rename="toBlock")] pub to_block: Option, - pub address: Option
, - pub topics: Option> + pub address: Option, + pub topics: Option>, +} + +impl Into for Filter { + fn into(self) -> EthFilter { + EthFilter { + from_block: self.from_block.map_or_else(|| BlockId::Earliest, Into::into), + to_block: self.to_block.map_or_else(|| BlockId::Latest, Into::into), + address: self.address.and_then(|address| match address { + VariadicValue::Null => None, + VariadicValue::Single(a) => Some(vec![a]), + VariadicValue::Multiple(a) => Some(a) + }), + topics: { + let mut iter = self.topics.map_or_else(Vec::new, |topics| topics.into_iter().take(4).map(|topic| match topic { + VariadicValue::Null => None, + VariadicValue::Single(t) => Some(vec![t]), + VariadicValue::Multiple(t) => Some(t) + }).filter_map(|m| m).collect()).into_iter(); + [iter.next(), iter.next(), iter.next(), iter.next()] + } + } + } } #[cfg(test)] @@ -65,9 +93,9 @@ mod tests { let s = r#"["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null, ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", "0x0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc"]]"#; let deserialized: Vec = serde_json::from_str(s).unwrap(); assert_eq!(deserialized, vec![ - Topic::Single(H256::from_str("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap()), - Topic::Null, - Topic::Multiple(vec![ + VariadicValue::Single(H256::from_str("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap()), + VariadicValue::Null, + VariadicValue::Multiple(vec![ H256::from_str("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap(), H256::from_str("0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc").unwrap() ]) diff --git a/rpc/src/v1/types/index.rs b/rpc/src/v1/types/index.rs index a77096fbf..e7cbbd255 100644 --- a/rpc/src/v1/types/index.rs +++ b/rpc/src/v1/types/index.rs @@ -30,7 +30,7 @@ impl Index { impl Deserialize for Index { fn deserialize(deserializer: &mut D) -> Result where D: Deserializer { - deserializer.visit(IndexVisitor) + deserializer.deserialize(IndexVisitor) } } @@ -41,8 +41,8 @@ impl Visitor for IndexVisitor { fn visit_str(&mut self, value: &str) -> Result where E: Error { match value { - _ if value.starts_with("0x") => usize::from_str_radix(&value[2..], 16).map(Index).map_err(|_| Error::syntax("invalid index")), - _ => value.parse::().map(Index).map_err(|_| Error::syntax("invalid index")) + _ if value.starts_with("0x") => usize::from_str_radix(&value[2..], 16).map(Index).map_err(|_| Error::custom("invalid index")), + _ => value.parse::().map(Index).map_err(|_| Error::custom("invalid index")) } } diff --git a/rpc/src/v1/types/log.rs b/rpc/src/v1/types/log.rs new file mode 100644 index 000000000..c8dfb1aec --- /dev/null +++ b/rpc/src/v1/types/log.rs @@ -0,0 +1,81 @@ +// 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::*; +use ethcore::log_entry::LocalizedLogEntry; +use v1::types::Bytes; + +#[derive(Debug, Serialize)] +pub struct Log { + pub address: Address, + pub topics: Vec, + pub data: Bytes, + #[serde(rename="blockHash")] + pub block_hash: H256, + #[serde(rename="blockNumber")] + pub block_number: U256, + #[serde(rename="transactionHash")] + pub transaction_hash: H256, + #[serde(rename="transactionIndex")] + pub transaction_index: U256, + #[serde(rename="logIndex")] + pub log_index: U256, +} + +impl From for Log { + fn from(e: LocalizedLogEntry) -> Log { + Log { + address: e.entry.address, + topics: e.entry.topics, + data: Bytes::new(e.entry.data), + block_hash: e.block_hash, + block_number: From::from(e.block_number), + transaction_hash: e.transaction_hash, + transaction_index: From::from(e.transaction_index), + log_index: From::from(e.log_index) + } + } +} + +#[cfg(test)] +mod tests { + use serde_json; + use std::str::FromStr; + use util::numbers::*; + use v1::types::{Bytes, Log}; + + #[test] + fn log_serialization() { + let s = r#"{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x04510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x00","logIndex":"0x01"}"#; + + let log = Log { + address: Address::from_str("33990122638b9132ca29c723bdf037f1a891a70c").unwrap(), + topics: vec![ + H256::from_str("a6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc").unwrap(), + H256::from_str("4861736852656700000000000000000000000000000000000000000000000000").unwrap() + ], + data: Bytes::new(vec![]), + block_hash: H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap(), + block_number: U256::from(0x4510c), + transaction_hash: H256::new(), + transaction_index: U256::zero(), + log_index: U256::one() + }; + + let serialized = serde_json::to_string(&log).unwrap(); + assert_eq!(serialized, s); + } +} diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index c4c6e8295..adf9be071 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -14,20 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -mod block; -mod block_number; -mod bytes; -mod filter; -mod index; -mod optionals; -mod sync; -mod transaction; +#[cfg(feature = "serde_macros")] +include!("mod.rs.in"); -pub use self::block::{Block, BlockTransactions}; -pub use self::block_number::BlockNumber; -pub use self::bytes::Bytes; -pub use self::filter::Filter; -pub use self::index::Index; -pub use self::optionals::OptionalValue; -pub use self::sync::{SyncStatus, SyncInfo}; -pub use self::transaction::Transaction; +#[cfg(not(feature = "serde_macros"))] +include!(concat!(env!("OUT_DIR"), "/mod.rs")); diff --git a/rpc/src/v1/types/mod.rs.in b/rpc/src/v1/types/mod.rs.in new file mode 100644 index 000000000..06b07b146 --- /dev/null +++ b/rpc/src/v1/types/mod.rs.in @@ -0,0 +1,42 @@ +// 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 . + +mod block; +mod block_number; +mod bytes; +mod filter; +mod index; +mod log; +mod optionals; +mod sync; +mod transaction; +mod transaction_request; +mod call_request; +mod receipt; + +pub use self::block::{Block, BlockTransactions}; +pub use self::block_number::BlockNumber; +pub use self::bytes::Bytes; +pub use self::filter::Filter; +pub use self::index::Index; +pub use self::log::Log; +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::call_request::CallRequest; +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..4bcfa3eb5 --- /dev/null +++ b/rpc/src/v1/types/receipt.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 . + +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(), + } + } +} + +#[cfg(test)] +mod tests { + use serde_json; + use std::str::FromStr; + use util::numbers::*; + use v1::types::{Bytes, Log, Receipt}; + + #[test] + fn receipt_serialization() { + let s = r#"{"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x00","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x04510c","cumulativeGasUsed":"0x20","gasUsed":"0x10","contractAddress":null,"logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x04510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x00","logIndex":"0x01"}]}"#; + + let receipt = Receipt { + transaction_hash: H256::zero(), + transaction_index: U256::zero(), + block_hash: H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap(), + block_number: U256::from(0x4510c), + cumulative_gas_used: U256::from(0x20), + gas_used: U256::from(0x10), + contract_address: None, + logs: vec![Log { + address: Address::from_str("33990122638b9132ca29c723bdf037f1a891a70c").unwrap(), + topics: vec![ + H256::from_str("a6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc").unwrap(), + H256::from_str("4861736852656700000000000000000000000000000000000000000000000000").unwrap() + ], + data: Bytes::new(vec![]), + block_hash: H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap(), + block_number: U256::from(0x4510c), + transaction_hash: H256::new(), + transaction_index: U256::zero(), + log_index: U256::one() + }] + }; + + let serialized = serde_json::to_string(&receipt).unwrap(); + assert_eq!(serialized, s); + } +} + diff --git a/rpc/src/v1/types/sync.rs b/rpc/src/v1/types/sync.rs index b5568acda..c0e480140 100644 --- a/rpc/src/v1/types/sync.rs +++ b/rpc/src/v1/types/sync.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use serde::{Serialize, Serializer}; -use util::uint::*; +use util::numbers::*; #[derive(Default, Debug, Serialize, PartialEq)] pub struct SyncInfo { diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index 0e9256ada..d809d19b4 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -14,8 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use util::hash::*; -use util::uint::*; +use util::numbers::*; use ethcore::transaction::{LocalizedTransaction, Action}; use v1::types::{Bytes, OptionalValue}; @@ -68,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 new file mode 100644 index 000000000..a9ed8a3f4 --- /dev/null +++ b/rpc/src/v1/types/transaction_request.rs @@ -0,0 +1,106 @@ +// 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::hash::Address; +use util::numbers::U256; +use v1::types::Bytes; + +#[derive(Debug, Default, PartialEq, Deserialize)] +pub struct TransactionRequest { + pub from: Address, + pub to: Option
, + #[serde(rename="gasPrice")] + pub gas_price: Option, + pub gas: Option, + pub value: Option, + pub data: Option, + pub nonce: Option, +} + +#[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; + use ethcore::transaction::{Transaction, Action}; + use v1::types::Bytes; + use super::*; + + #[test] + fn transaction_request_deserialize() { + let s = r#"{ + "from":"0x0000000000000000000000000000000000000001", + "to":"0x0000000000000000000000000000000000000002", + "gasPrice":"0x1", + "gas":"0x2", + "value":"0x3", + "data":"0x123456", + "nonce":"0x4" + }"#; + let deserialized: TransactionRequest = serde_json::from_str(s).unwrap(); + + assert_eq!(deserialized, TransactionRequest { + from: Address::from(1), + to: Some(Address::from(2)), + gas_price: Some(U256::from(1)), + gas: Some(U256::from(2)), + value: Some(U256::from(3)), + data: Some(Bytes::new(vec![0x12, 0x34, 0x56])), + nonce: Some(U256::from(4)), + }); + } + + #[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"}"#; + let deserialized: TransactionRequest = serde_json::from_str(s).unwrap(); + + assert_eq!(deserialized, TransactionRequest { + from: Address::from(1), + to: None, + gas_price: None, + gas: None, + value: None, + data: None, + nonce: None, + }); + } +} diff --git a/sync/Cargo.toml b/sync/Cargo.toml index 8eb6a1bee..91732fea8 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Ethcore blockchain sync" name = "ethsync" -version = "0.1.0" +version = "1.1.0" license = "GPL-3.0" authors = ["Ethcore usize { @@ -60,6 +64,7 @@ const MAX_BODIES_TO_SEND: usize = 256; const MAX_HEADERS_TO_SEND: usize = 512; const MAX_NODE_DATA_TO_SEND: usize = 1024; const MAX_RECEIPTS_TO_SEND: usize = 1024; +const MAX_RECEIPTS_HEADERS_TO_SEND: usize = 256; const MAX_HEADERS_TO_REQUEST: usize = 512; const MAX_BODIES_TO_REQUEST: usize = 256; const MIN_PEERS_PROPAGATION: usize = 4; @@ -80,9 +85,7 @@ const NODE_DATA_PACKET: u8 = 0x0e; const GET_RECEIPTS_PACKET: u8 = 0x0f; const RECEIPTS_PACKET: u8 = 0x10; -const NETWORK_ID: U256 = ONE_U256; //TODO: get this from parent - -const CONNECTION_TIMEOUT_SEC: f64 = 30f64; +const CONNECTION_TIMEOUT_SEC: f64 = 5f64; struct Header { /// Header data @@ -116,6 +119,7 @@ pub enum SyncState { } /// Syncing status and statistics +#[derive(Clone)] pub struct SyncStatus { /// State pub state: SyncState, @@ -135,6 +139,8 @@ pub struct SyncStatus { pub num_peers: usize, /// Total number of active peers pub num_active_peers: usize, + /// Heap memory used in bytes + pub mem_used: usize, } #[derive(PartialEq, Eq, Debug, Clone)] @@ -202,14 +208,20 @@ pub struct ChainSync { /// True if common block for our and remote chain has been found have_common_block: bool, /// Last propagated block number - last_send_block_number: BlockNumber, + last_sent_block_number: BlockNumber, + /// Max blocks to download ahead + max_download_ahead_blocks: usize, + /// Network ID + network_id: U256, + /// Miner + miner: Arc, } type RlpResponseResult = Result, PacketDecodeError>; impl ChainSync { /// Create a new instance of syncing strategy. - pub fn new() -> ChainSync { + pub fn new(config: SyncConfig, miner: Arc) -> ChainSync { ChainSync { state: SyncState::NotSynced, starting_block: 0, @@ -225,7 +237,10 @@ impl ChainSync { last_imported_hash: None, syncing_difficulty: U256::from(0u64), have_common_block: false, - last_send_block_number: 0, + last_sent_block_number: 0, + max_download_ahead_blocks: max(MAX_HEADERS_TO_REQUEST, config.max_download_ahead_blocks), + network_id: config.network_id, + miner: miner, } } @@ -237,10 +252,19 @@ impl ChainSync { start_block_number: self.starting_block, last_imported_block_number: self.last_imported_block, highest_block_number: self.highest_block, - blocks_received: match self.last_imported_block { None => 0, Some(x) => x - self.starting_block }, - blocks_total: match self.highest_block { None => 0, Some(x) => x - self.starting_block }, + blocks_received: match self.last_imported_block { Some(x) if x > self.starting_block => x - self.starting_block, _ => 0 }, + blocks_total: match self.highest_block { Some(x) if x > self.starting_block => x - self.starting_block, _ => 0 }, num_peers: self.peers.len(), num_active_peers: self.peers.values().filter(|p| p.asking != PeerAsking::Nothing).count(), + mem_used: + // TODO: https://github.com/servo/heapsize/pull/50 + // self.downloading_hashes.heap_size_of_children() + //+ self.downloading_bodies.heap_size_of_children() + //+ self.downloading_hashes.heap_size_of_children() + self.headers.heap_size_of_children() + + self.bodies.heap_size_of_children() + + self.peers.heap_size_of_children() + + self.header_ids.heap_size_of_children(), } } @@ -251,7 +275,7 @@ impl ChainSync { } - #[allow(for_kv_map)] // Because it's not possible to get `values_mut()` + #[cfg_attr(feature="dev", allow(for_kv_map))] // Because it's not possible to get `values_mut()` /// Rest sync. Clear all downloaded data but keep the queue fn reset(&mut self) { self.downloading_headers.clear(); @@ -270,12 +294,9 @@ impl ChainSync { /// Restart sync pub fn restart(&mut self, io: &mut SyncIo) { self.reset(); - self.last_imported_block = None; - self.last_imported_hash = None; self.starting_block = 0; self.highest_block = None; self.have_common_block = false; - io.chain().clear_queue(); self.starting_block = io.chain().chain_info().best_block_number; self.state = SyncState::NotSynced; } @@ -307,19 +328,19 @@ impl ChainSync { trace!(target: "sync", "Peer {} genesis hash not matched", peer_id); return Ok(()); } - if peer.network_id != NETWORK_ID { + if peer.network_id != self.network_id { io.disable_peer(peer_id); trace!(target: "sync", "Peer {} network id not matched", peer_id); return Ok(()); } self.peers.insert(peer_id.clone(), peer); - info!(target: "sync", "Connected {}:{}", peer_id, io.peer_info(peer_id)); + debug!(target: "sync", "Connected {}:{}", peer_id, io.peer_info(peer_id)); self.sync_peer(io, peer_id, false); Ok(()) } - #[allow(cyclomatic_complexity)] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] /// Called by peer once it has new block headers during sync fn on_peer_block_headers(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { self.reset_peer_asking(peer_id, PeerAsking::BlockHeaders); @@ -338,7 +359,7 @@ impl ChainSync { for i in 0..item_count { let info: BlockHeader = try!(r.val_at(i)); let number = BlockNumber::from(info.number); - if number <= self.current_base_block() || self.headers.have_item(&number) { + if (number <= self.current_base_block() && self.have_common_block) || self.headers.have_item(&number) { trace!(target: "sync", "Skipping existing block header"); continue; } @@ -348,11 +369,17 @@ impl ChainSync { } let hash = info.hash(); match io.chain().block_status(BlockId::Hash(hash.clone())) { - BlockStatus::InChain => { - self.have_common_block = true; - self.last_imported_block = Some(number); - self.last_imported_hash = Some(hash.clone()); - trace!(target: "sync", "Found common header {} ({})", number, hash); + BlockStatus::InChain | BlockStatus::Queued => { + if !self.have_common_block || self.current_base_block() < number { + self.last_imported_block = Some(number); + self.last_imported_hash = Some(hash.clone()); + } + if !self.have_common_block { + self.have_common_block = true; + trace!(target: "sync", "Found common header {} ({})", number, hash); + } else { + trace!(target: "sync", "Header already in chain {} ({})", number, hash); + } }, _ => { if self.have_common_block { @@ -375,6 +402,12 @@ impl ChainSync { debug!(target: "sync", "Mismatched block header {}", number + 1); self.remove_downloaded_blocks(number + 1); } + if self.have_common_block && number < self.current_base_block() + 1 { + // unkown header + debug!(target: "sync", "Old block header {:?} ({}) is unknown, restarting sync", hash, number); + self.restart(io); + return Ok(()); + } } let hdr = Header { data: try!(r.at(i)).as_raw().to_vec(), @@ -436,7 +469,7 @@ impl ChainSync { trace!(target: "sync", "Got body {}", n); } None => { - debug!(target: "sync", "Ignored unknown block body"); + trace!(target: "sync", "Ignored unknown/stale block body"); } } } @@ -446,11 +479,16 @@ impl ChainSync { } /// Called by peer once it has new block bodies + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn on_peer_new_block(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { let block_rlp = try!(r.at(0)); let header_rlp = try!(block_rlp.at(0)); let h = header_rlp.as_raw().sha3(); trace!(target: "sync", "{} -> NewBlock ({})", peer_id, h); + if !self.have_common_block { + trace!(target: "sync", "NewBlock ignored while seeking"); + return Ok(()); + } let header: BlockHeader = try!(header_rlp.as_val()); let mut unknown = false; { @@ -459,21 +497,25 @@ impl ChainSync { peer.latest_number = Some(header.number()); } // TODO: Decompose block and add to self.headers and self.bodies instead - if header.number == From::from(self.current_base_block() + 1) { + if header.number <= From::from(self.current_base_block() + 1) { match io.chain().import_block(block_rlp.as_raw().to_vec()) { - Err(ImportError::AlreadyInChain) => { + Err(Error::Import(ImportError::AlreadyInChain)) => { trace!(target: "sync", "New block already in chain {:?}", h); }, - Err(ImportError::AlreadyQueued) => { + Err(Error::Import(ImportError::AlreadyQueued)) => { trace!(target: "sync", "New block already queued {:?}", h); }, Ok(_) => { - self.last_imported_block = Some(header.number); - trace!(target: "sync", "New block queued {:?}", h); + if self.current_base_block() < header.number { + self.last_imported_block = Some(header.number); + self.last_imported_hash = Some(header.hash()); + self.remove_downloaded_blocks(header.number); + } + trace!(target: "sync", "New block queued {:?} ({})", h, header.number); }, - Err(ImportError::UnknownParent) => { + Err(Error::Block(BlockError::UnknownParent(p))) => { unknown = true; - trace!(target: "sync", "New block with unknown parent {:?}", h); + trace!(target: "sync", "New block with unknown parent ({:?}) {:?}", p, h); }, Err(e) => { debug!(target: "sync", "Bad new block {:?} : {:?}", h, e); @@ -545,7 +587,7 @@ impl ChainSync { pub fn on_peer_aborting(&mut self, io: &mut SyncIo, peer: PeerId) { trace!(target: "sync", "== Disconnecting {}", peer); if self.peers.contains_key(&peer) { - info!(target: "sync", "Disconnected {}", peer); + debug!(target: "sync", "Disconnected {}", peer); self.clear_peer_download(peer); self.peers.remove(&peer); self.continue_sync(io); @@ -555,7 +597,10 @@ impl ChainSync { /// Called when a new peer is connected pub fn on_peer_connected(&mut self, io: &mut SyncIo, peer: PeerId) { trace!(target: "sync", "== Connected {}", peer); - self.send_status(io, peer); + if let Err(e) = self.send_status(io) { + debug!(target:"sync", "Error sending status request: {:?}", e); + io.disable_peer(peer); + } } /// Resume downloading @@ -608,7 +653,7 @@ impl ChainSync { self.request_headers_by_hash(io, peer_id, &peer_latest, 1, 0, false); } else if self.state == SyncState::Blocks && io.chain().block_status(BlockId::Hash(peer_latest)) == BlockStatus::Unknown { - self.request_blocks(io, peer_id); + self.request_blocks(io, peer_id, false); } } @@ -616,8 +661,28 @@ impl ChainSync { match self.last_imported_block { None => 0, Some(x) => x } } + fn find_block_bodies_hashes_to_request(&self, ignore_others: bool) -> (Vec, Vec) { + let mut needed_bodies: Vec = Vec::new(); + let mut needed_numbers: Vec = Vec::new(); + + if self.have_common_block && !self.headers.is_empty() && self.headers.range_iter().next().unwrap().0 == self.current_base_block() + 1 { + if let Some((start, ref items)) = self.headers.range_iter().next() { + let mut index: BlockNumber = 0; + while index != items.len() as BlockNumber && needed_bodies.len() < MAX_BODIES_TO_REQUEST { + let block = start + index; + if ignore_others || (!self.downloading_bodies.contains(&block) && !self.bodies.have_item(&block)) { + needed_bodies.push(items[index as usize].hash.clone()); + needed_numbers.push(block); + } + index += 1; + } + } + } + (needed_bodies, needed_numbers) + } + /// Find some headers or blocks to download for a peer. - fn request_blocks(&mut self, io: &mut SyncIo, peer_id: PeerId) { + fn request_blocks(&mut self, io: &mut SyncIo, peer_id: PeerId, ignore_others: bool) { self.clear_peer_download(peer_id); if io.chain().queue_info().is_full() { @@ -626,81 +691,78 @@ impl ChainSync { } // check to see if we need to download any block bodies first - let mut needed_bodies: Vec = Vec::new(); - let mut needed_numbers: Vec = Vec::new(); + let (needed_bodies, needed_numbers) = self.find_block_bodies_hashes_to_request(ignore_others); + if !needed_bodies.is_empty() { + let (head, _) = self.headers.range_iter().next().unwrap(); + if needed_numbers.first().unwrap() - head > self.max_download_ahead_blocks as BlockNumber { + trace!(target: "sync", "{}: Stalled download ({} vs {}), helping with downloading block bodies", peer_id, needed_numbers.first().unwrap(), head); + self.request_blocks(io, peer_id, true); + } else { + self.downloading_bodies.extend(needed_numbers.iter()); + replace(&mut self.peers.get_mut(&peer_id).unwrap().asking_blocks, needed_numbers); + self.request_bodies(io, peer_id, needed_bodies); + } + return; + } - if self.have_common_block && !self.headers.is_empty() && self.headers.range_iter().next().unwrap().0 == self.current_base_block() + 1 { - for (start, ref items) in self.headers.range_iter() { - if needed_bodies.len() >= MAX_BODIES_TO_REQUEST { + // check if need to download headers + let mut start = 0; + if !self.have_common_block { + // download backwards until common block is found 1 header at a time + let chain_info = io.chain().chain_info(); + start = match self.last_imported_block { + Some(n) => n, + None => chain_info.best_block_number, + }; + if !self.headers.is_empty() { + start = min(start, self.headers.range_iter().next().unwrap().0 - 1); + } + if start == 0 { + self.have_common_block = true; //reached genesis + self.last_imported_hash = Some(chain_info.genesis_hash); + self.last_imported_block = Some(0); + } + } + if self.have_common_block { + let mut headers: Vec = Vec::new(); + let mut prev = self.current_base_block() + 1; + let head = self.headers.range_iter().next().map(|(h, _)| h); + for (next, ref items) in self.headers.range_iter() { + if !headers.is_empty() { break; } - let mut index: BlockNumber = 0; - while index != items.len() as BlockNumber && needed_bodies.len() < MAX_BODIES_TO_REQUEST { - let block = start + index; - if !self.downloading_bodies.contains(&block) && !self.bodies.have_item(&block) { - needed_bodies.push(items[index as usize].hash.clone()); - needed_numbers.push(block); - self.downloading_bodies.insert(block); - } - index += 1; + if next <= prev { + prev = next + items.len() as BlockNumber; + continue; } + let mut block = prev; + while block < next && headers.len() < MAX_HEADERS_TO_REQUEST { + if ignore_others || !self.downloading_headers.contains(&(block as BlockNumber)) { + headers.push(block as BlockNumber); + } + block += 1; + } + prev = next + items.len() as BlockNumber; + } + + if !headers.is_empty() { + start = headers[0]; + if head.is_some() && start > head.unwrap() && start - head.unwrap() > self.max_download_ahead_blocks as BlockNumber { + trace!(target: "sync", "{}: Stalled download ({} vs {}), helping with downloading headers", peer_id, start, head.unwrap()); + self.request_blocks(io, peer_id, true); + return; + } + let count = headers.len(); + self.downloading_headers.extend(headers.iter()); + replace(&mut self.peers.get_mut(&peer_id).unwrap().asking_blocks, headers); + assert!(!self.headers.have_item(&start)); + self.request_headers_by_number(io, peer_id, start, count, 0, false); } - } - if !needed_bodies.is_empty() { - replace(&mut self.peers.get_mut(&peer_id).unwrap().asking_blocks, needed_numbers); - self.request_bodies(io, peer_id, needed_bodies); } else { - // check if need to download headers - let mut start = 0usize; - if !self.have_common_block { - // download backwards until common block is found 1 header at a time - let chain_info = io.chain().chain_info(); - start = chain_info.best_block_number as usize; - if !self.headers.is_empty() { - start = min(start, self.headers.range_iter().next().unwrap().0 as usize - 1); - } - if start == 0 { - self.have_common_block = true; //reached genesis - self.last_imported_hash = Some(chain_info.genesis_hash); - self.last_imported_block = Some(0); - } - } - if self.have_common_block { - let mut headers: Vec = Vec::new(); - let mut prev = self.current_base_block() + 1; - for (next, ref items) in self.headers.range_iter() { - if !headers.is_empty() { - break; - } - if next <= prev { - prev = next + items.len() as BlockNumber; - continue; - } - let mut block = prev; - while block < next && headers.len() < MAX_HEADERS_TO_REQUEST { - if !self.downloading_headers.contains(&(block as BlockNumber)) { - headers.push(block as BlockNumber); - self.downloading_headers.insert(block as BlockNumber); - } - block += 1; - } - prev = next + items.len() as BlockNumber; - } - - if !headers.is_empty() { - start = headers[0] as usize; - let count = headers.len(); - replace(&mut self.peers.get_mut(&peer_id).unwrap().asking_blocks, headers); - assert!(!self.headers.have_item(&(start as BlockNumber))); - self.request_headers_by_number(io, peer_id, start as BlockNumber, count, 0, false); - } - } - else { - // continue search for common block - self.downloading_headers.insert(start as BlockNumber); - self.request_headers_by_number(io, peer_id, start as BlockNumber, 1, 0, false); - } + // continue search for common block + self.downloading_headers.insert(start); + self.request_headers_by_number(io, peer_id, start, 1, 0, false); } } @@ -728,7 +790,7 @@ impl ChainSync { { let headers = self.headers.range_iter().next().unwrap(); let bodies = self.bodies.range_iter().next().unwrap(); - if headers.0 != bodies.0 || headers.0 != self.current_base_block() + 1 { + if headers.0 != bodies.0 || headers.0 > self.current_base_block() + 1 { return; } @@ -750,12 +812,12 @@ impl ChainSync { } match io.chain().import_block(block_rlp.out()) { - Err(ImportError::AlreadyInChain) => { + Err(Error::Import(ImportError::AlreadyInChain)) => { trace!(target: "sync", "Block already in chain {:?}", h); self.last_imported_block = Some(headers.0 + i as BlockNumber); self.last_imported_hash = Some(h.clone()); }, - Err(ImportError::AlreadyQueued) => { + Err(Error::Import(ImportError::AlreadyQueued)) => { trace!(target: "sync", "Block already queued {:?}", h); self.last_imported_block = Some(headers.0 + i as BlockNumber); self.last_imported_hash = Some(h.clone()); @@ -792,20 +854,14 @@ impl ChainSync { /// Remove downloaded bocks/headers starting from specified number. /// Used to recover from an error and re-download parts of the chain detected as bad. fn remove_downloaded_blocks(&mut self, start: BlockNumber) { - for n in self.headers.get_tail(&start) { - if let Some(ref header_data) = self.headers.find_item(&n) { - let header_to_delete = HeaderView::new(&header_data.data); - let header_id = HeaderId { - transactions_root: header_to_delete.transactions_root(), - uncles: header_to_delete.uncles_hash() - }; - self.header_ids.remove(&header_id); - } - self.downloading_bodies.remove(&n); - self.downloading_headers.remove(&n); - } - self.headers.remove_tail(&start); - self.bodies.remove_tail(&start); + let ids = self.header_ids.drain().filter(|&(_, v)| v < start).collect(); + self.header_ids = ids; + let hdrs = self.downloading_headers.drain().filter(|v| *v < start).collect(); + self.downloading_headers = hdrs; + let bodies = self.downloading_bodies.drain().filter(|v| *v < start).collect(); + self.downloading_bodies = bodies; + self.headers.remove_from(&start); + self.bodies.remove_from(&start); } /// Request headers from a peer by block hash @@ -861,9 +917,8 @@ impl ChainSync { } match sync.send(peer_id, packet_id, packet) { Err(e) => { - warn!(target:"sync", "Error sending request: {:?}", e); + debug!(target:"sync", "Error sending request: {:?}", e); sync.disable_peer(peer_id); - self.on_peer_aborting(sync, peer_id); } Ok(_) => { let mut peer = self.peers.get_mut(&peer_id).unwrap(); @@ -876,30 +931,44 @@ impl ChainSync { /// Generic packet sender fn send_packet(&mut self, sync: &mut SyncIo, peer_id: PeerId, packet_id: PacketId, packet: Bytes) { if let Err(e) = sync.send(peer_id, packet_id, packet) { - warn!(target:"sync", "Error sending packet: {:?}", e); + debug!(target:"sync", "Error sending packet: {:?}", e); sync.disable_peer(peer_id); - self.on_peer_aborting(sync, peer_id); } } /// Called when peer sends us new transactions - fn on_peer_transactions(&mut self, _io: &mut SyncIo, _peer_id: PeerId, _r: &UntrustedRlp) -> Result<(), PacketDecodeError> { - Ok(()) + fn on_peer_transactions(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> 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); + + let mut transactions = Vec::with_capacity(item_count); + for i in 0..item_count { + let tx: SignedTransaction = try!(r.val_at(i)); + transactions.push(tx); + } + let chain = io.chain(); + let fetch_account = |a: &Address| AccountDetails { + nonce: chain.nonce(a), + balance: chain.balance(a), + }; + let _ = self.miner.import_transactions(transactions, fetch_account); + Ok(()) } /// Send Status message - fn send_status(&mut self, io: &mut SyncIo, peer_id: PeerId) { + fn send_status(&mut self, io: &mut SyncIo) -> Result<(), UtilError> { let mut packet = RlpStream::new_list(5); let chain = io.chain().chain_info(); packet.append(&(PROTOCOL_VERSION as u32)); - packet.append(&NETWORK_ID); //TODO: network id + packet.append(&self.network_id); packet.append(&chain.total_difficulty); packet.append(&chain.best_block_hash); packet.append(&chain.genesis_hash); - //TODO: handle timeout for status request - if let Err(e) = io.send(peer_id, STATUS_PACKET, packet.out()) { - warn!(target:"sync", "Error sending status request: {:?}", e); - io.disable_peer(peer_id); - } + io.respond(STATUS_PACKET, packet.out()) } /// Respond to GetBlockHeaders request @@ -927,19 +996,19 @@ impl ChainSync { if reverse { number = min(last, number); } else { - number = max(1, number); + number = max(0, number); } let max_count = min(MAX_HEADERS_TO_SEND, max_headers); let mut count = 0; let mut data = Bytes::new(); let inc = (skip + 1) as BlockNumber; - while number <= last && number > 0 && count < max_count { + while number <= last && count < max_count { if let Some(mut hdr) = io.chain().block_header(BlockId::Number(number)) { data.append(&mut hdr); count += 1; } if reverse { - if number <= inc { + if number <= inc || number == 0 { break; } number -= inc; @@ -1004,17 +1073,20 @@ impl ChainSync { debug!(target: "sync", "Empty GetReceipts request, ignoring."); return Ok(None); } - count = min(count, MAX_RECEIPTS_TO_SEND); - let mut added = 0usize; + count = min(count, MAX_RECEIPTS_HEADERS_TO_SEND); + let mut added_headers = 0usize; + let mut added_receipts = 0usize; let mut data = Bytes::new(); for i in 0..count { - if let Some(mut hdr) = io.chain().block_receipts(&try!(rlp.val_at::(i))) { - data.append(&mut hdr); - added += 1; + if let Some(mut receipts_bytes) = io.chain().block_receipts(&try!(rlp.val_at::(i))) { + data.append(&mut receipts_bytes); + added_receipts += receipts_bytes.len(); + added_headers += 1; + if added_receipts > MAX_RECEIPTS_TO_SEND { break; } } } - let mut rlp_result = RlpStream::new_list(added); - rlp_result.append_raw(&data, added); + let mut rlp_result = RlpStream::new_list(added_headers); + rlp_result.append_raw(&data, added_headers); Ok(Some((RECEIPTS_PACKET, rlp_result))) } @@ -1039,7 +1111,7 @@ impl ChainSync { let rlp = UntrustedRlp::new(data); if packet_id != STATUS_PACKET && !self.peers.contains_key(&peer) { - warn!(target:"sync", "Unexpected packet from unregistered peer: {}:{}", peer, io.peer_info(peer)); + debug!(target:"sync", "Unexpected packet from unregistered peer: {}:{}", peer, io.peer_info(peer)); return; } let result = match packet_id { @@ -1124,9 +1196,7 @@ impl ChainSync { } /// returns peer ids that have less blocks than our chain - fn get_lagging_peers(&mut self, io: &SyncIo) -> Vec<(PeerId, BlockNumber)> { - let chain = io.chain(); - let chain_info = chain.chain_info(); + fn get_lagging_peers(&mut self, chain_info: &BlockChainInfo, io: &SyncIo) -> Vec<(PeerId, BlockNumber)> { let latest_hash = chain_info.best_block_hash; let latest_number = chain_info.best_block_number; self.peers.iter_mut().filter_map(|(&id, ref mut peer_info)| @@ -1144,10 +1214,10 @@ impl ChainSync { .collect::>() } - /// propagades latest block to lagging peers - fn propagade_blocks(&mut self, local_best: &H256, best_number: BlockNumber, io: &mut SyncIo) -> usize { + /// propagates latest block to lagging peers + fn propagate_blocks(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo) -> usize { let updated_peers = { - let lagging_peers = self.get_lagging_peers(io); + let lagging_peers = self.get_lagging_peers(chain_info, io); // sqrt(x)/x scaled to max u32 let fraction = (self.peers.len() as f64).powf(-0.5).mul(u32::max_value() as f64).round() as u32; @@ -1164,30 +1234,30 @@ impl ChainSync { for peer_id in updated_peers { let rlp = ChainSync::create_latest_block_rlp(io.chain()); self.send_packet(io, peer_id, NEW_BLOCK_PACKET, rlp); - self.peers.get_mut(&peer_id).unwrap().latest_hash = local_best.clone(); - self.peers.get_mut(&peer_id).unwrap().latest_number = Some(best_number); + self.peers.get_mut(&peer_id).unwrap().latest_hash = chain_info.best_block_hash.clone(); + self.peers.get_mut(&peer_id).unwrap().latest_number = Some(chain_info.best_block_number); sent = sent + 1; } sent } - /// propagades new known hashes to all peers - fn propagade_new_hashes(&mut self, local_best: &H256, best_number: BlockNumber, io: &mut SyncIo) -> usize { - let updated_peers = self.get_lagging_peers(io); + /// propagates new known hashes to all peers + fn propagate_new_hashes(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo) -> usize { + let updated_peers = self.get_lagging_peers(chain_info, io); let mut sent = 0; - let last_parent = HeaderView::new(&io.chain().block_header(BlockId::Hash(local_best.clone())).unwrap()).parent_hash(); + let last_parent = HeaderView::new(&io.chain().block_header(BlockId::Hash(chain_info.best_block_hash.clone())).unwrap()).parent_hash(); for (peer_id, peer_number) in updated_peers { let mut peer_best = self.peers.get(&peer_id).unwrap().latest_hash.clone(); - if best_number - peer_number > MAX_PEERS_PROPAGATION as BlockNumber { - // If we think peer is too far behind just end one latest hash + if chain_info.best_block_number - peer_number > MAX_PEERS_PROPAGATION as BlockNumber { + // If we think peer is too far behind just send one latest hash peer_best = last_parent.clone(); } - sent = sent + match ChainSync::create_new_hashes_rlp(io.chain(), &peer_best, &local_best) { + sent = sent + match ChainSync::create_new_hashes_rlp(io.chain(), &peer_best, &chain_info.best_block_hash) { Some(rlp) => { { let peer = self.peers.get_mut(&peer_id).unwrap(); - peer.latest_hash = local_best.clone(); - peer.latest_number = Some(best_number); + peer.latest_hash = chain_info.best_block_hash.clone(); + peer.latest_number = Some(chain_info.best_block_number); } self.send_packet(io, peer_id, NEW_BLOCK_HASHES_PACKET, rlp); 1 @@ -1198,22 +1268,36 @@ impl ChainSync { sent } + fn propagate_latest_blocks(&mut self, io: &mut SyncIo) { + let chain_info = io.chain().chain_info(); + if (((chain_info.best_block_number as i64) - (self.last_sent_block_number as i64)).abs() as BlockNumber) < MAX_PEER_LAG_PROPAGATION { + let blocks = self.propagate_blocks(&chain_info, io); + let hashes = self.propagate_new_hashes(&chain_info, io); + if blocks != 0 || hashes != 0 { + trace!(target: "sync", "Sent latest {} blocks and {} hashes to peers.", blocks, hashes); + } + } + self.last_sent_block_number = chain_info.best_block_number; + } + /// Maintain other peers. Send out any new blocks and transactions pub fn maintain_sync(&mut self, io: &mut SyncIo) { self.check_resume(io); } - /// should be called once chain has new block, triggers the latest block propagation - pub fn chain_blocks_verified(&mut self, io: &mut SyncIo) { - let chain = io.chain().chain_info(); - if (((chain.best_block_number as i64) - (self.last_send_block_number as i64)).abs() as BlockNumber) < MAX_PEER_LAG_PROPAGATION { - let blocks = self.propagade_blocks(&chain.best_block_hash, chain.best_block_number, io); - let hashes = self.propagade_new_hashes(&chain.best_block_hash, chain.best_block_number, io); - if blocks != 0 || hashes != 0 { - trace!(target: "sync", "Sent latest {} blocks and {} hashes to peers.", blocks, hashes); - } + /// 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]) { + 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); } - self.last_send_block_number = chain.best_block_number; + // TODO [todr] propagate transactions? + } + + pub fn chain_new_head(&mut self, io: &mut SyncIo) { + self.miner.update_sealing(io.chain()); } } @@ -1221,10 +1305,13 @@ impl ChainSync { mod tests { use tests::helpers::*; use super::*; + use ::SyncConfig; use util::*; use super::{PeerInfo, PeerAsking}; + use ethcore::views::BlockView; use ethcore::header::*; use ethcore::client::*; + use ethminer::{Miner, MinerService}; fn get_dummy_block(order: u32, parent_hash: H256) -> Bytes { let mut header = Header::new(); @@ -1297,7 +1384,7 @@ mod tests { assert!(rlp_result.is_some()); // the length of two rlp-encoded receipts - assert_eq!(597, rlp_result.unwrap().1.out().len()); + assert_eq!(603, rlp_result.unwrap().1.out().len()); let mut sync = dummy_sync_with_peer(H256::new()); io.sender = Some(2usize); @@ -1334,7 +1421,7 @@ mod tests { } fn dummy_sync_with_peer(peer_latest_hash: H256) -> ChainSync { - let mut sync = ChainSync::new(); + let mut sync = ChainSync::new(SyncConfig::default(), Miner::new()); sync.peers.insert(0, PeerInfo { protocol_version: 0, @@ -1354,12 +1441,13 @@ mod tests { #[test] fn finds_lagging_peers() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, false); + client.add_blocks(100, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(10)); + let chain_info = client.chain_info(); let io = TestIo::new(&mut client, &mut queue, None); - let lagging_peers = sync.get_lagging_peers(&io); + let lagging_peers = sync.get_lagging_peers(&chain_info, &io); assert_eq!(1, lagging_peers.len()) } @@ -1367,7 +1455,7 @@ mod tests { #[test] fn calculates_tree_for_lagging_peer() { let mut client = TestBlockChainClient::new(); - client.add_blocks(15, false); + client.add_blocks(15, EachBlockWith::Uncle); let start = client.block_hash_delta_minus(4); let end = client.block_hash_delta_minus(2); @@ -1384,14 +1472,13 @@ mod tests { #[test] fn sends_new_hashes_to_lagging_peer() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, false); + client.add_blocks(100, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); - let best_hash = client.chain_info().best_block_hash.clone(); - let best_number = client.chain_info().best_block_number; + let chain_info = client.chain_info(); let mut io = TestIo::new(&mut client, &mut queue, None); - let peer_count = sync.propagade_new_hashes(&best_hash, best_number, &mut io); + let peer_count = sync.propagate_new_hashes(&chain_info, &mut io); // 1 message should be send assert_eq!(1, io.queue.len()); @@ -1404,14 +1491,12 @@ mod tests { #[test] fn sends_latest_block_to_lagging_peer() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, false); + client.add_blocks(100, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); - let best_hash = client.chain_info().best_block_hash.clone(); - let best_number = client.chain_info().best_block_number; + let chain_info = client.chain_info(); let mut io = TestIo::new(&mut client, &mut queue, None); - - let peer_count = sync.propagade_blocks(&best_hash, best_number, &mut io); + let peer_count = sync.propagate_blocks(&chain_info, &mut io); // 1 message should be send assert_eq!(1, io.queue.len()); @@ -1424,12 +1509,13 @@ mod tests { #[test] fn handles_peer_new_block_mallformed() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, false); + client.add_blocks(10, EachBlockWith::Uncle); let block_data = get_dummy_block(11, client.chain_info().best_block_hash); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); + sync.have_common_block = true; let mut io = TestIo::new(&mut client, &mut queue, None); let block = UntrustedRlp::new(&block_data); @@ -1442,7 +1528,7 @@ mod tests { #[test] fn handles_peer_new_block() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, false); + client.add_blocks(10, EachBlockWith::Uncle); let block_data = get_dummy_blocks(11, client.chain_info().best_block_hash); @@ -1460,7 +1546,7 @@ mod tests { #[test] fn handles_peer_new_block_empty() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, false); + client.add_blocks(10, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let mut io = TestIo::new(&mut client, &mut queue, None); @@ -1476,7 +1562,7 @@ mod tests { #[test] fn handles_peer_new_hashes() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, false); + client.add_blocks(10, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let mut io = TestIo::new(&mut client, &mut queue, None); @@ -1492,7 +1578,7 @@ mod tests { #[test] fn handles_peer_new_hashes_empty() { let mut client = TestBlockChainClient::new(); - client.add_blocks(10, false); + client.add_blocks(10, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); let mut io = TestIo::new(&mut client, &mut queue, None); @@ -1510,14 +1596,13 @@ mod tests { #[test] fn hashes_rlp_mutually_acceptable() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, false); + client.add_blocks(100, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); - let best_hash = client.chain_info().best_block_hash.clone(); - let best_number = client.chain_info().best_block_number; + let chain_info = client.chain_info(); let mut io = TestIo::new(&mut client, &mut queue, None); - sync.propagade_new_hashes(&best_hash, best_number, &mut io); + sync.propagate_new_hashes(&chain_info, &mut io); let data = &io.queue[0].data.clone(); let result = sync.on_peer_new_hashes(&mut io, 0, &UntrustedRlp::new(&data)); @@ -1529,17 +1614,126 @@ mod tests { #[test] fn block_rlp_mutually_acceptable() { let mut client = TestBlockChainClient::new(); - client.add_blocks(100, false); + client.add_blocks(100, EachBlockWith::Uncle); let mut queue = VecDeque::new(); let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5)); - let best_hash = client.chain_info().best_block_hash.clone(); - let best_number = client.chain_info().best_block_number; + let chain_info = client.chain_info(); let mut io = TestIo::new(&mut client, &mut queue, None); - sync.propagade_blocks(&best_hash, best_number, &mut io); + sync.propagate_blocks(&chain_info, &mut io); let data = &io.queue[0].data.clone(); let result = sync.on_peer_new_block(&mut io, 0, &UntrustedRlp::new(&data)); assert!(result.is_ok()); } + + #[test] + fn should_add_transactions_to_queue() { + // 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)]; + + // 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().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.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] + fn returns_requested_block_headers() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + let mut queue = VecDeque::new(); + let io = TestIo::new(&mut client, &mut queue, None); + + let mut rlp = RlpStream::new_list(4); + rlp.append(&0u64); + rlp.append(&10u64); + rlp.append(&0u64); + rlp.append(&0u64); + let data = rlp.out(); + + let response = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&data)); + + assert!(response.is_ok()); + let (_, rlp_stream) = response.unwrap().unwrap(); + let response_data = rlp_stream.out(); + let rlp = UntrustedRlp::new(&response_data); + assert!(rlp.at(0).is_ok()); + assert!(rlp.at(9).is_ok()); + } + + #[test] + fn returns_requested_block_headers_reverse() { + let mut client = TestBlockChainClient::new(); + client.add_blocks(100, EachBlockWith::Uncle); + let mut queue = VecDeque::new(); + let io = TestIo::new(&mut client, &mut queue, None); + + let mut rlp = RlpStream::new_list(4); + rlp.append(&15u64); + rlp.append(&15u64); + rlp.append(&0u64); + rlp.append(&1u64); + let data = rlp.out(); + + let response = ChainSync::return_block_headers(&io, &UntrustedRlp::new(&data)); + + assert!(response.is_ok()); + let (_, rlp_stream) = response.unwrap().unwrap(); + let response_data = rlp_stream.out(); + let rlp = UntrustedRlp::new(&response_data); + assert!(rlp.at(0).is_ok()); + assert!(rlp.at(14).is_ok()); + assert!(!rlp.at(15).is_ok()); + } } 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 74edab4a5..a4f6eff38 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -15,11 +15,12 @@ // along with Parity. If not, see . #![warn(missing_docs)] -#![feature(plugin)] -#![feature(augmented_assignments)] -#![plugin(clippy)] +#![cfg_attr(feature="dev", feature(plugin))] +#![cfg_attr(feature="dev", plugin(clippy))] // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. -#![allow(clone_on_copy)] +#![cfg_attr(feature="dev", allow(clone_on_copy))] +// In most cases it expresses function flow better +#![cfg_attr(feature="dev", allow(if_not_else))] //! Blockchain sync module //! Implements ethereum protocol version 63 as specified here: @@ -31,18 +32,21 @@ //! extern crate ethcore_util as util; //! extern crate ethcore; //! extern crate ethsync; +//! extern crate ethminer; //! use std::env; //! use std::sync::Arc; //! use util::network::{NetworkService, NetworkConfiguration}; -//! use ethcore::client::Client; -//! use ethsync::EthSync; +//! use ethcore::client::{Client, ClientConfig}; +//! use ethsync::{EthSync, SyncConfig}; +//! use ethminer::Miner; //! use ethcore::ethereum; //! //! fn main() { //! let mut service = NetworkService::start(NetworkConfiguration::new()).unwrap(); //! let dir = env::temp_dir(); -//! let client = Client::new(ethereum::new_frontier(), &dir, service.io().channel()).unwrap(); -//! EthSync::register(&mut service, client); +//! let client = Client::new(ClientConfig::default(), ethereum::new_frontier(), &dir, service.io().channel()).unwrap(); +//! let miner = Miner::new(); +//! EthSync::register(&mut service, SyncConfig::default(), client, miner); //! } //! ``` @@ -51,18 +55,23 @@ extern crate log; #[macro_use] extern crate ethcore_util as util; extern crate ethcore; +extern crate ethminer; extern crate env_logger; extern crate time; extern crate rand; +#[macro_use] +extern crate heapsize; use std::ops::*; use std::sync::*; -use ethcore::client::Client; use util::network::{NetworkProtocolHandler, NetworkService, NetworkContext, PeerId}; -use util::io::TimerToken; -use chain::ChainSync; +use util::TimerToken; +use util::{U256, ONE_U256}; +use ethcore::client::Client; use ethcore::service::SyncMessage; +use ethminer::Miner; use io::NetSyncIo; +use chain::ChainSync; mod chain; mod io; @@ -71,6 +80,29 @@ mod range_collection; #[cfg(test)] mod tests; +/// Sync configuration +pub struct SyncConfig { + /// Max blocks to download ahead + pub max_download_ahead_blocks: usize, + /// Network ID + pub network_id: U256, +} + +impl Default for SyncConfig { + fn default() -> SyncConfig { + SyncConfig { + max_download_ahead_blocks: 20000, + network_id: ONE_U256, + } + } +} + +/// Current sync status +pub trait SyncProvider: Send + Sync { + /// Get sync status + fn status(&self) -> SyncStatus; +} + /// Ethereum network protocol handler pub struct EthSync { /// Shared blockchain client. TODO: this should evetually become an IPC endpoint @@ -83,20 +115,15 @@ pub use self::chain::{SyncStatus, SyncState}; impl EthSync { /// Creates and register protocol with the network service - pub fn register(service: &mut NetworkService, chain: Arc) -> Arc { + pub fn register(service: &mut NetworkService, config: SyncConfig, chain: Arc, miner: Arc) -> Arc { let sync = Arc::new(EthSync { chain: chain, - sync: RwLock::new(ChainSync::new()), + sync: RwLock::new(ChainSync::new(config, miner)), }); service.register_protocol(sync.clone(), "eth", &[62u8, 63u8]).expect("Error registering eth protocol handler"); sync } - /// Get sync status - pub fn status(&self) -> SyncStatus { - self.sync.read().unwrap().status() - } - /// Stop sync pub fn stop(&mut self, io: &mut NetworkContext) { self.sync.write().unwrap().abort(&mut NetSyncIo::new(io, self.chain.deref())); @@ -108,6 +135,13 @@ impl EthSync { } } +impl SyncProvider for EthSync { + /// Get sync status + fn status(&self) -> SyncStatus { + self.sync.read().unwrap().status() + } +} + impl NetworkProtocolHandler for EthSync { fn initialize(&self, io: &NetworkContext) { io.register_timer(0, 1000).expect("Error registering sync timer"); @@ -131,8 +165,16 @@ impl NetworkProtocolHandler for EthSync { } fn message(&self, io: &NetworkContext, message: &SyncMessage) { - if let SyncMessage::BlockVerified = *message { - self.sync.write().unwrap().chain_blocks_verified(&mut NetSyncIo::new(io, self.chain.deref())); + match *message { + SyncMessage::NewChainBlocks { ref imported, ref invalid, ref enacted, ref retracted } => { + let mut sync_io = NetSyncIo::new(io, self.chain.deref()); + self.sync.write().unwrap().chain_new_blocks(&mut sync_io, imported, invalid, enacted, retracted); + }, + 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/sync/src/range_collection.rs b/sync/src/range_collection.rs index c3333ab63..0628df401 100644 --- a/sync/src/range_collection.rs +++ b/sync/src/range_collection.rs @@ -42,6 +42,8 @@ pub trait RangeCollection { fn remove_head(&mut self, start: &K); /// Remove all elements >= `start` in the range that contains `start` fn remove_tail(&mut self, start: &K); + /// Remove all elements >= `start` + fn remove_from(&mut self, start: &K); /// Remove all elements >= `tail` fn insert_item(&mut self, key: K, value: V); /// Get an iterator over ranges @@ -137,6 +139,28 @@ impl RangeCollection for Vec<(K, Vec)> where K: Ord + PartialEq + } } + /// Remove the element and all following it. + fn remove_from(&mut self, key: &K) { + match self.binary_search_by(|&(k, _)| k.cmp(key).reverse()) { + Ok(index) => { self.drain(.. index + 1); }, + Err(index) =>{ + let mut empty = false; + match self.get_mut(index) { + Some(&mut (ref k, ref mut v)) if k <= key && (*k + FromUsize::from_usize(v.len())) > *key => { + v.truncate((*key - *k).to_usize()); + empty = v.is_empty(); + } + _ => {} + } + if empty { + self.drain(.. index + 1); + } else { + self.drain(.. index); + } + }, + } + } + /// Remove range elements up to key fn remove_head(&mut self, key: &K) { if *key == FromUsize::from_usize(0) { @@ -207,7 +231,7 @@ impl RangeCollection for Vec<(K, Vec)> where K: Ord + PartialEq + } #[test] -#[allow(cyclomatic_complexity)] +#[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn test_range() { use std::cmp::{Ordering}; @@ -272,5 +296,22 @@ fn test_range() { assert_eq!(r.range_iter().cmp(vec![(2, &['b'][..])]), Ordering::Equal); r.remove_tail(&2); assert_eq!(r.range_iter().next(), None); + + let mut r = ranges.clone(); + r.remove_from(&20); + assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..]), (16, &['p', 'q', 'r'][..])]), Ordering::Equal); + r.remove_from(&18); + assert!(!r.have_item(&18)); + assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..]), (16, &['p', 'q'][..])]), Ordering::Equal); + r.remove_from(&16); + assert!(!r.have_item(&16)); + assert_eq!(r.range_iter().cmp(vec![(2, &['b', 'c', 'd'][..])]), Ordering::Equal); + r.remove_from(&3); + assert_eq!(r.range_iter().cmp(vec![(2, &['b'][..])]), Ordering::Equal); + r.remove_from(&1); + assert_eq!(r.range_iter().next(), None); + let mut r = ranges.clone(); + r.remove_from(&2); + assert_eq!(r.range_iter().next(), None); } diff --git a/sync/src/tests/chain.rs b/sync/src/tests/chain.rs index 1dd9a1e78..eebbdb164 100644 --- a/sync/src/tests/chain.rs +++ b/sync/src/tests/chain.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use util::*; -use ethcore::client::{BlockChainClient, BlockId}; +use ethcore::client::{BlockChainClient, BlockId, EachBlockWith}; use io::SyncIo; use chain::{SyncState}; use super::helpers::*; @@ -24,8 +24,8 @@ use super::helpers::*; fn two_peers() { ::env_logger::init().ok(); let mut net = TestNet::new(3); - net.peer_mut(1).chain.add_blocks(1000, false); - net.peer_mut(2).chain.add_blocks(1000, false); + net.peer_mut(1).chain.add_blocks(1000, EachBlockWith::Uncle); + net.peer_mut(2).chain.add_blocks(1000, EachBlockWith::Uncle); net.sync(); assert!(net.peer(0).chain.block(BlockId::Number(1000)).is_some()); assert_eq!(net.peer(0).chain.blocks.read().unwrap().deref(), net.peer(1).chain.blocks.read().unwrap().deref()); @@ -35,8 +35,8 @@ fn two_peers() { fn status_after_sync() { ::env_logger::init().ok(); let mut net = TestNet::new(3); - net.peer_mut(1).chain.add_blocks(1000, false); - net.peer_mut(2).chain.add_blocks(1000, false); + net.peer_mut(1).chain.add_blocks(1000, EachBlockWith::Uncle); + net.peer_mut(2).chain.add_blocks(1000, EachBlockWith::Uncle); net.sync(); let status = net.peer(0).sync.status(); assert_eq!(status.state, SyncState::Idle); @@ -45,8 +45,8 @@ fn status_after_sync() { #[test] fn takes_few_steps() { let mut net = TestNet::new(3); - net.peer_mut(1).chain.add_blocks(100, false); - net.peer_mut(2).chain.add_blocks(100, false); + net.peer_mut(1).chain.add_blocks(100, EachBlockWith::Uncle); + net.peer_mut(2).chain.add_blocks(100, EachBlockWith::Uncle); let total_steps = net.sync(); assert!(total_steps < 7); } @@ -56,8 +56,9 @@ fn empty_blocks() { ::env_logger::init().ok(); let mut net = TestNet::new(3); for n in 0..200 { - net.peer_mut(1).chain.add_blocks(5, n % 2 == 0); - net.peer_mut(2).chain.add_blocks(5, n % 2 == 0); + let with = if n % 2 == 0 { EachBlockWith::Nothing } else { EachBlockWith::Uncle }; + net.peer_mut(1).chain.add_blocks(5, with.clone()); + net.peer_mut(2).chain.add_blocks(5, with); } net.sync(); assert!(net.peer(0).chain.block(BlockId::Number(1000)).is_some()); @@ -68,14 +69,14 @@ fn empty_blocks() { fn forked() { ::env_logger::init().ok(); let mut net = TestNet::new(3); - net.peer_mut(0).chain.add_blocks(300, false); - net.peer_mut(1).chain.add_blocks(300, false); - net.peer_mut(2).chain.add_blocks(300, false); - net.peer_mut(0).chain.add_blocks(100, true); //fork - net.peer_mut(1).chain.add_blocks(200, false); - net.peer_mut(2).chain.add_blocks(200, false); - net.peer_mut(1).chain.add_blocks(100, false); //fork between 1 and 2 - net.peer_mut(2).chain.add_blocks(10, true); + net.peer_mut(0).chain.add_blocks(300, EachBlockWith::Uncle); + net.peer_mut(1).chain.add_blocks(300, EachBlockWith::Uncle); + net.peer_mut(2).chain.add_blocks(300, EachBlockWith::Uncle); + net.peer_mut(0).chain.add_blocks(100, EachBlockWith::Nothing); //fork + net.peer_mut(1).chain.add_blocks(200, EachBlockWith::Uncle); + net.peer_mut(2).chain.add_blocks(200, EachBlockWith::Uncle); + net.peer_mut(1).chain.add_blocks(100, EachBlockWith::Uncle); //fork between 1 and 2 + net.peer_mut(2).chain.add_blocks(10, EachBlockWith::Nothing); // peer 1 has the best chain of 601 blocks let peer1_chain = net.peer(1).chain.numbers.read().unwrap().clone(); net.sync(); @@ -87,8 +88,8 @@ fn forked() { #[test] fn restart() { let mut net = TestNet::new(3); - net.peer_mut(1).chain.add_blocks(1000, false); - net.peer_mut(2).chain.add_blocks(1000, false); + net.peer_mut(1).chain.add_blocks(1000, EachBlockWith::Uncle); + net.peer_mut(2).chain.add_blocks(1000, EachBlockWith::Uncle); net.sync_steps(8); @@ -109,8 +110,8 @@ fn status_empty() { #[test] fn status_packet() { let mut net = TestNet::new(2); - net.peer_mut(0).chain.add_blocks(100, false); - net.peer_mut(1).chain.add_blocks(1, false); + net.peer_mut(0).chain.add_blocks(100, EachBlockWith::Uncle); + net.peer_mut(1).chain.add_blocks(1, EachBlockWith::Uncle); net.start(); @@ -121,15 +122,15 @@ fn status_packet() { } #[test] -fn propagade_hashes() { +fn propagate_hashes() { let mut net = TestNet::new(6); - net.peer_mut(1).chain.add_blocks(10, false); + net.peer_mut(1).chain.add_blocks(10, EachBlockWith::Uncle); net.sync(); - net.peer_mut(0).chain.add_blocks(10, false); + net.peer_mut(0).chain.add_blocks(10, EachBlockWith::Uncle); net.sync(); - net.trigger_block_verified(0); //first event just sets the marker - net.trigger_block_verified(0); + net.trigger_chain_new_blocks(0); //first event just sets the marker + net.trigger_chain_new_blocks(0); // 5 peers to sync assert_eq!(5, net.peer(0).queue.len()); @@ -147,14 +148,14 @@ fn propagade_hashes() { } #[test] -fn propagade_blocks() { +fn propagate_blocks() { let mut net = TestNet::new(2); - net.peer_mut(1).chain.add_blocks(10, false); + net.peer_mut(1).chain.add_blocks(10, EachBlockWith::Uncle); net.sync(); - net.peer_mut(0).chain.add_blocks(10, false); - net.trigger_block_verified(0); //first event just sets the marker - net.trigger_block_verified(0); + net.peer_mut(0).chain.add_blocks(10, EachBlockWith::Uncle); + net.trigger_chain_new_blocks(0); //first event just sets the marker + net.trigger_chain_new_blocks(0); assert!(!net.peer(0).queue.is_empty()); // NEW_BLOCK_PACKET @@ -164,7 +165,7 @@ fn propagade_blocks() { #[test] fn restart_on_malformed_block() { let mut net = TestNet::new(2); - net.peer_mut(1).chain.add_blocks(10, false); + net.peer_mut(1).chain.add_blocks(10, EachBlockWith::Uncle); net.peer_mut(1).chain.corrupt_block(6); net.sync_steps(10); diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index c561b65a3..b3e62ccc6 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -15,245 +15,11 @@ // along with Parity. If not, see . use util::*; -use ethcore::client::{BlockChainClient, BlockStatus, TreeRoute, BlockChainInfo, TransactionId, BlockId}; -use ethcore::block_queue::BlockQueueInfo; -use ethcore::header::{Header as BlockHeader, BlockNumber}; -use ethcore::error::*; +use ethcore::client::{TestBlockChainClient, BlockChainClient}; use io::SyncIo; -use chain::{ChainSync}; -use ethcore::receipt::Receipt; -use ethcore::transaction::LocalizedTransaction; - -pub struct TestBlockChainClient { - pub blocks: RwLock>, - pub numbers: RwLock>, - pub genesis_hash: H256, - pub last_hash: RwLock, - pub difficulty: RwLock, -} - -impl TestBlockChainClient { - pub fn new() -> TestBlockChainClient { - - let mut client = TestBlockChainClient { - blocks: RwLock::new(HashMap::new()), - numbers: RwLock::new(HashMap::new()), - genesis_hash: H256::new(), - last_hash: RwLock::new(H256::new()), - difficulty: RwLock::new(From::from(0)), - }; - client.add_blocks(1, true); // add genesis block - client.genesis_hash = client.last_hash.read().unwrap().clone(); - client - } - - pub fn add_blocks(&mut self, count: usize, empty: bool) { - let len = self.numbers.read().unwrap().len(); - for n in len..(len + count) { - let mut header = BlockHeader::new(); - header.difficulty = From::from(n); - header.parent_hash = self.last_hash.read().unwrap().clone(); - header.number = n as BlockNumber; - let mut uncles = RlpStream::new_list(if empty {0} else {1}); - if !empty { - let mut uncle_header = BlockHeader::new(); - uncle_header.difficulty = From::from(n); - uncle_header.parent_hash = self.last_hash.read().unwrap().clone(); - uncle_header.number = n as BlockNumber; - uncles.append(&uncle_header); - header.uncles_hash = uncles.as_raw().sha3(); - } - let mut rlp = RlpStream::new_list(3); - rlp.append(&header); - rlp.append_raw(&rlp::NULL_RLP, 1); - rlp.append_raw(uncles.as_raw(), 1); - self.import_block(rlp.as_raw().to_vec()).unwrap(); - } - } - - pub fn corrupt_block(&mut self, n: BlockNumber) { - let hash = self.block_hash(BlockId::Number(n)).unwrap(); - let mut header: BlockHeader = decode(&self.block_header(BlockId::Number(n)).unwrap()); - header.parent_hash = H256::new(); - let mut rlp = RlpStream::new_list(3); - rlp.append(&header); - rlp.append_raw(&rlp::NULL_RLP, 1); - rlp.append_raw(&rlp::NULL_RLP, 1); - self.blocks.write().unwrap().insert(hash, rlp.out()); - } - - pub fn block_hash_delta_minus(&mut self, delta: usize) -> H256 { - let blocks_read = self.numbers.read().unwrap(); - let index = blocks_read.len() - delta; - blocks_read[&index].clone() - } - - fn block_hash(&self, id: BlockId) -> Option { - match id { - BlockId::Hash(hash) => Some(hash), - BlockId::Number(n) => self.numbers.read().unwrap().get(&(n as usize)).cloned(), - BlockId::Earliest => self.numbers.read().unwrap().get(&0).cloned(), - BlockId::Latest => self.numbers.read().unwrap().get(&(self.numbers.read().unwrap().len() - 1)).cloned() - } - } -} - -impl BlockChainClient for TestBlockChainClient { - fn block_total_difficulty(&self, _id: BlockId) -> Option { - Some(U256::zero()) - } - - fn code(&self, _address: &Address) -> Option { - unimplemented!(); - } - - fn transaction(&self, _id: TransactionId) -> Option { - unimplemented!(); - } - - fn block_header(&self, id: BlockId) -> Option { - self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec())) - } - - fn block_body(&self, id: BlockId) -> Option { - self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| { - let mut stream = RlpStream::new_list(2); - stream.append_raw(Rlp::new(&r).at(1).as_raw(), 1); - stream.append_raw(Rlp::new(&r).at(2).as_raw(), 1); - stream.out() - })) - } - - fn block(&self, id: BlockId) -> Option { - self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).cloned()) - } - - fn block_status(&self, id: BlockId) -> BlockStatus { - match id { - BlockId::Number(number) if (number as usize) < self.blocks.read().unwrap().len() => BlockStatus::InChain, - BlockId::Hash(ref hash) if self.blocks.read().unwrap().get(hash).is_some() => BlockStatus::InChain, - _ => BlockStatus::Unknown - } - } - - // works only if blocks are one after another 1 -> 2 -> 3 - fn tree_route(&self, from: &H256, to: &H256) -> Option { - Some(TreeRoute { - ancestor: H256::new(), - index: 0, - blocks: { - let numbers_read = self.numbers.read().unwrap(); - let mut adding = false; - - let mut blocks = Vec::new(); - for (_, hash) in numbers_read.iter().sort_by(|tuple1, tuple2| tuple1.0.cmp(tuple2.0)) { - if hash == to { - if adding { - blocks.push(hash.clone()); - } - adding = false; - break; - } - if hash == from { - adding = true; - } - if adding { - blocks.push(hash.clone()); - } - } - if adding { Vec::new() } else { blocks } - } - }) - } - - // TODO: returns just hashes instead of node state rlp(?) - fn state_data(&self, hash: &H256) -> Option { - // starts with 'f' ? - if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") { - let mut rlp = RlpStream::new(); - rlp.append(&hash.clone()); - return Some(rlp.out()); - } - None - } - - fn block_receipts(&self, hash: &H256) -> Option { - // starts with 'f' ? - if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") { - let receipt = Receipt::new( - H256::zero(), - U256::zero(), - vec![]); - let mut rlp = RlpStream::new(); - rlp.append(&receipt); - return Some(rlp.out()); - } - None - } - - fn import_block(&self, b: Bytes) -> ImportResult { - let header = Rlp::new(&b).val_at::(0); - let h = header.hash(); - let number: usize = header.number as usize; - if number > self.blocks.read().unwrap().len() { - panic!("Unexpected block number. Expected {}, got {}", self.blocks.read().unwrap().len(), number); - } - if number > 0 { - match self.blocks.read().unwrap().get(&header.parent_hash) { - Some(parent) => { - let parent = Rlp::new(parent).val_at::(0); - if parent.number != (header.number - 1) { - panic!("Unexpected block parent"); - } - }, - None => { - panic!("Unknown block parent {:?} for block {}", header.parent_hash, number); - } - } - } - let len = self.numbers.read().unwrap().len(); - if number == len { - *self.difficulty.write().unwrap().deref_mut() += header.difficulty; - mem::replace(self.last_hash.write().unwrap().deref_mut(), h.clone()); - self.blocks.write().unwrap().insert(h.clone(), b); - self.numbers.write().unwrap().insert(number, h.clone()); - let mut parent_hash = header.parent_hash; - if number > 0 { - let mut n = number - 1; - while n > 0 && self.numbers.read().unwrap()[&n] != parent_hash { - *self.numbers.write().unwrap().get_mut(&n).unwrap() = parent_hash.clone(); - n -= 1; - parent_hash = Rlp::new(&self.blocks.read().unwrap()[&parent_hash]).val_at::(0).parent_hash; - } - } - } - else { - self.blocks.write().unwrap().insert(h.clone(), b.to_vec()); - } - Ok(h) - } - - fn queue_info(&self) -> BlockQueueInfo { - BlockQueueInfo { - verified_queue_size: 0, - unverified_queue_size: 0, - verifying_queue_size: 0, - } - } - - fn clear_queue(&self) { - } - - fn chain_info(&self) -> BlockChainInfo { - BlockChainInfo { - total_difficulty: *self.difficulty.read().unwrap(), - pending_total_difficulty: *self.difficulty.read().unwrap(), - genesis_hash: self.genesis_hash.clone(), - best_block_hash: self.last_hash.read().unwrap().clone(), - best_block_number: self.blocks.read().unwrap().len() as BlockNumber - 1, - } - } -} +use chain::ChainSync; +use ethminer::Miner; +use ::SyncConfig; pub struct TestIo<'p> { pub chain: &'p mut TestBlockChainClient, @@ -327,7 +93,7 @@ impl TestNet { for _ in 0..n { net.peers.push(TestPeer { chain: TestBlockChainClient::new(), - sync: ChainSync::new(), + sync: ChainSync::new(SyncConfig::default(), Miner::new()), queue: VecDeque::new(), }); } @@ -400,8 +166,8 @@ impl TestNet { self.peers.iter().all(|p| p.queue.is_empty()) } - pub fn trigger_block_verified(&mut self, peer_id: usize) { + pub fn trigger_chain_new_blocks(&mut self, peer_id: usize) { let mut peer = self.peer_mut(peer_id); - peer.sync.chain_blocks_verified(&mut TestIo::new(&mut peer.chain, &mut peer.queue, None)); + peer.sync.chain_new_blocks(&mut TestIo::new(&mut peer.chain, &mut peer.queue, None), &[], &[], &[], &[]); } } diff --git a/test.sh b/test.sh new file mode 100755 index 000000000..4957fd762 --- /dev/null +++ b/test.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# Running Parity Full Test Sute + +cargo test --features ethcore/json-tests $1 \ + -p ethash \ + -p ethcore-util \ + -p ethcore \ + -p ethsync \ + -p ethcore-rpc \ + -p parity \ + -p ethminer \ + -p bigint diff --git a/util/Cargo.toml b/util/Cargo.toml index b1e9bbc1e..1584d2b2e 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -3,8 +3,9 @@ description = "Ethcore utility library" homepage = "http://ethcore.io" license = "GPL-3.0" name = "ethcore-util" -version = "0.9.0" +version = "1.1.0" authors = ["Ethcore "] +build = "build.rs" [dependencies] log = "0.3" @@ -15,18 +16,31 @@ mio = "0.5.0" rand = "0.3.12" time = "0.1.34" tiny-keccak = "1.0" -rocksdb = "0.3" +rocksdb = { git = "https://github.com/arkpar/rust-rocksdb.git" } lazy_static = "0.1" -eth-secp256k1 = { git = "https://github.com/arkpar/rust-secp256k1.git" } +eth-secp256k1 = { git = "https://github.com/ethcore/rust-secp256k1" } rust-crypto = "0.2.34" elastic-array = "0.4" -heapsize = "0.2" +heapsize = "0.3" itertools = "0.4" crossbeam = "0.2" -slab = { git = "https://github.com/arkpar/slab.git" } +slab = "0.1" sha3 = { path = "sha3" } -serde = "0.6.7" -clippy = "0.0.41" +serde = "0.7.0" +clippy = { version = "0.0.54", optional = true } json-tests = { path = "json-tests" } -target_info = "0.1.0" igd = "0.4.2" +ethcore-devtools = { path = "../devtools" } +libc = "0.2.7" +vergen = "0.1" +target_info = "0.1" +bigint = { path = "bigint" } +chrono = "0.2" + +[features] +default = [] +dev = ["clippy"] + +[build-dependencies] +vergen = "*" +rustc_version = "0.1.0" diff --git a/util/benches/bigint.rs b/util/benches/bigint.rs new file mode 100644 index 000000000..3f4164d18 --- /dev/null +++ b/util/benches/bigint.rs @@ -0,0 +1,104 @@ +// 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 . + +//! benchmarking for rlp +//! should be started with: +//! ```bash +//! multirust run nightly cargo bench +//! ``` + +#![feature(test)] +#![feature(asm)] + +extern crate test; +extern crate ethcore_util; +extern crate rand; + +use test::{Bencher, black_box}; +use ethcore_util::numbers::*; + +#[bench] +fn u256_add(b: &mut Bencher) { + b.iter(|| { + let n = black_box(10000); + (0..n).fold(U256([rand::random::(), rand::random::(), rand::random::(), rand::random::()]), |old, new| { old.overflowing_add(U256::from(new)).0 }) + }); +} + +#[bench] +fn u256_sub(b: &mut Bencher) { + b.iter(|| { + let n = black_box(10000); + (0..n).fold(U256([rand::random::(), rand::random::(), rand::random::(), rand::random::()]), |old, new| { old.overflowing_sub(U256::from(new)).0 }) + }); +} + +#[bench] +fn u512_sub(b: &mut Bencher) { + b.iter(|| { + let n = black_box(10000); + (0..n).fold( + U512([ + rand::random::(), rand::random::(), rand::random::(), rand::random::(), + rand::random::(), rand::random::(), rand::random::(), rand::random::() + ]), + |old, new| { + let p = new % 2; + old.overflowing_sub(U512([p, p, p, p, p, p, p, new])).0 + } + ) + }); +} + +#[bench] +fn u512_add(b: &mut Bencher) { + b.iter(|| { + let n = black_box(10000); + (0..n).fold(U512([0, 0, 0, 0, 0, 0, 0, 0]), + |old, new| { old.overflowing_add(U512([new, new, new, new, new, new, new, new])).0 }) + }); +} + +#[bench] +fn u256_mul(b: &mut Bencher) { + b.iter(|| { + let n = black_box(10000); + (0..n).fold(U256([rand::random::(), rand::random::(), rand::random::(), rand::random::()]), |old, new| { old.overflowing_mul(U256::from(new)).0 }) + }); +} + + +#[bench] +fn u256_full_mul(b: &mut Bencher) { + b.iter(|| { + let n = black_box(10000); + (0..n).fold(U256([rand::random::(), rand::random::(), rand::random::(), rand::random::()]), + |old, _new| { + let U512(ref u512words) = old.full_mul(U256([rand::random::(), rand::random::(), rand::random::(), rand::random::()])); + U256([u512words[0], u512words[2], u512words[2], u512words[3]]) + }) + }); +} + + +#[bench] +fn u128_mul(b: &mut Bencher) { + b.iter(|| { + let n = black_box(10000); + (0..n).fold(U128([12345u64, 0u64]), |old, new| { old.overflowing_mul(U128::from(new)).0 }) + }); +} + diff --git a/util/benches/rlp.rs b/util/benches/rlp.rs index e94cb3635..4a983f369 100644 --- a/util/benches/rlp.rs +++ b/util/benches/rlp.rs @@ -28,7 +28,7 @@ extern crate ethcore_util; use test::Bencher; use std::str::FromStr; use ethcore_util::rlp::*; -use ethcore_util::uint::U256; +use ethcore_util::numbers::U256; #[bench] fn bench_stream_u64_value(b: &mut Bencher) { diff --git a/util/bigint/Cargo.toml b/util/bigint/Cargo.toml new file mode 100644 index 000000000..1bd2b994e --- /dev/null +++ b/util/bigint/Cargo.toml @@ -0,0 +1,22 @@ +[package] +description = "Rust-assembler implementation of big integers arithmetic" +homepage = "http://ethcore.io" +license = "GPL-3.0" +name = "bigint" +version = "0.1.0" +authors = ["Ethcore "] +build = "build.rs" + +[build-dependencies] +rustc_version = "0.1" + +[dependencies] +rustc-serialize = "0.3" +arrayvec = "0.3" +rand = "0.3.12" +serde = "0.7.0" +heapsize = "0.3" + +[features] +x64asm_arithmetic=[] +rust_arithmetic=[] diff --git a/util/bigint/build.rs b/util/bigint/build.rs new file mode 100644 index 000000000..248823229 --- /dev/null +++ b/util/bigint/build.rs @@ -0,0 +1,25 @@ +// 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_version; + +use rustc_version::{version_meta, Channel}; + +fn main() { + if let Channel::Nightly = version_meta().channel { + println!("cargo:rustc-cfg=asm_available"); + } +} diff --git a/util/bigint/src/lib.rs b/util/bigint/src/lib.rs new file mode 100644 index 000000000..149878538 --- /dev/null +++ b/util/bigint/src/lib.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 . + +#![cfg_attr(asm_available, feature(asm))] + +extern crate rustc_serialize; +extern crate serde; +#[macro_use] extern crate heapsize; + +pub mod uint; diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs new file mode 100644 index 000000000..7bc6007ed --- /dev/null +++ b/util/bigint/src/uint.rs @@ -0,0 +1,2152 @@ +// 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 . + +// Code derived from original work by Andrew Poelstra + +// Rust Bitcoin Library +// Written in 2014 by +// Andrew Poelstra +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to +// the public domain worldwide. This software is distributed without +// any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. +// If not, see . +// + +//! Big unsigned integer types +//! +//! Implementation of a various large-but-fixed sized unsigned integer types. +//! The functions here are designed to be fast. +//! + +#[cfg(all(asm_available, target_arch="x86_64"))] +use std::mem; +use std::fmt; +use std::cmp; + +use std::str::{FromStr}; +use std::convert::From; +use std::hash::{Hash, Hasher}; +use std::ops::*; +use std::cmp::*; + +use serde; +use rustc_serialize::hex::{FromHex, FromHexError, ToHex}; + + +macro_rules! impl_map_from { + ($thing:ident, $from:ty, $to:ty) => { + impl From<$from> for $thing { + fn from(value: $from) -> $thing { + From::from(value as $to) + } + } + } +} + +#[cfg(not(all(asm_available, target_arch="x86_64")))] +macro_rules! uint_overflowing_add { + ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ({ + uint_overflowing_add_reg!($name, $n_words, $self_expr, $other) + }) +} + +macro_rules! uint_overflowing_add_reg { + ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ({ + let $name(ref me) = $self_expr; + let $name(ref you) = $other; + + let mut ret = [0u64; $n_words]; + let mut carry = 0u64; + + for i in 0..$n_words { + let (res1, overflow1) = me[i].overflowing_add(you[i]); + let (res2, overflow2) = res1.overflowing_add(carry); + + ret[i] = res2; + carry = overflow1 as u64 + overflow2 as u64; + } + + ($name(ret), carry > 0) + }) +} + +#[cfg(all(asm_available, target_arch="x86_64"))] +macro_rules! uint_overflowing_add { + (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ + let mut result: [u64; 4] = unsafe { mem::uninitialized() }; + let self_t: &[u64; 4] = unsafe { &mem::transmute($self_expr) }; + let other_t: &[u64; 4] = unsafe { &mem::transmute($other) }; + + let overflow: u8; + unsafe { + asm!(" + add $9, $0 + adc $10, $1 + adc $11, $2 + adc $12, $3 + setc %al + " + : "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), "={al}"(overflow) + : "0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]), + "mr"(other_t[0]), "mr"(other_t[1]), "mr"(other_t[2]), "mr"(other_t[3]) + : + : + ); + } + (U256(result), overflow != 0) + }); + (U512, $n_words: expr, $self_expr: expr, $other: expr) => ({ + let mut result: [u64; 8] = unsafe { mem::uninitialized() }; + let self_t: &[u64; 8] = unsafe { &mem::transmute($self_expr) }; + let other_t: &[u64; 8] = unsafe { &mem::transmute($other) }; + + let overflow: u8; + + unsafe { + asm!(" + add $15, $0 + adc $16, $1 + adc $17, $2 + adc $18, $3 + lodsq + adc $11, %rax + stosq + lodsq + adc $12, %rax + stosq + lodsq + adc $13, %rax + stosq + lodsq + adc $14, %rax + stosq + setc %al + + ": "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), + + "={al}"(overflow) /* $0 - $4 */ + + : "{rdi}"(&result[4] as *const u64) /* $5 */ + "{rsi}"(&other_t[4] as *const u64) /* $6 */ + "0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]), + "m"(self_t[4]), "m"(self_t[5]), "m"(self_t[6]), "m"(self_t[7]), + /* $7 - $14 */ + + "mr"(other_t[0]), "mr"(other_t[1]), "mr"(other_t[2]), "mr"(other_t[3]), + "m"(other_t[4]), "m"(other_t[5]), "m"(other_t[6]), "m"(other_t[7]) /* $15 - $22 */ + : "rdi", "rsi" + : + ); + } + (U512(result), overflow != 0) + }); + + ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ( + uint_overflowing_add_reg!($name, $n_words, $self_expr, $other) + ) +} + +#[cfg(not(all(asm_available, target_arch="x86_64")))] +macro_rules! uint_overflowing_sub { + ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ + uint_overflowing_sub_reg!($name, $n_words, $self_expr, $other) + }) +} + +macro_rules! uint_overflowing_sub_reg { + ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ + let $name(ref me) = $self_expr; + let $name(ref you) = $other; + + let mut ret = [0u64; $n_words]; + let mut carry = 0u64; + + for i in 0..$n_words { + let (res1, overflow1) = me[i].overflowing_sub(you[i]); + let (res2, overflow2) = res1.overflowing_sub(carry); + + ret[i] = res2; + carry = overflow1 as u64 + overflow2 as u64; + } + + ($name(ret), carry > 0) + + }) +} + +#[cfg(all(asm_available, target_arch="x86_64"))] +macro_rules! uint_overflowing_sub { + (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ + let mut result: [u64; 4] = unsafe { mem::uninitialized() }; + let self_t: &[u64; 4] = unsafe { &mem::transmute($self_expr) }; + let other_t: &[u64; 4] = unsafe { &mem::transmute($other) }; + + let overflow: u8; + unsafe { + asm!(" + sub $9, $0 + sbb $10, $1 + sbb $11, $2 + sbb $12, $3 + setb %al + " + : "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), "={al}"(overflow) + : "0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]), "mr"(other_t[0]), "mr"(other_t[1]), "mr"(other_t[2]), "mr"(other_t[3]) + : + : + ); + } + (U256(result), overflow != 0) + }); + (U512, $n_words: expr, $self_expr: expr, $other: expr) => ({ + let mut result: [u64; 8] = unsafe { mem::uninitialized() }; + let self_t: &[u64; 8] = unsafe { &mem::transmute($self_expr) }; + let other_t: &[u64; 8] = unsafe { &mem::transmute($other) }; + + let overflow: u8; + + unsafe { + asm!(" + sub $15, $0 + sbb $16, $1 + sbb $17, $2 + sbb $18, $3 + lodsq + sbb $19, %rax + stosq + lodsq + sbb $20, %rax + stosq + lodsq + sbb $21, %rax + stosq + lodsq + sbb $22, %rax + stosq + setb %al + " + : "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), + + "={al}"(overflow) /* $0 - $4 */ + + : "{rdi}"(&result[4] as *const u64) /* $5 */ + "{rsi}"(&self_t[4] as *const u64) /* $6 */ + "0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]), + "m"(self_t[4]), "m"(self_t[5]), "m"(self_t[6]), "m"(self_t[7]), + /* $7 - $14 */ + + "m"(other_t[0]), "m"(other_t[1]), "m"(other_t[2]), "m"(other_t[3]), + "m"(other_t[4]), "m"(other_t[5]), "m"(other_t[6]), "m"(other_t[7]) /* $15 - $22 */ + : "rdi", "rsi" + : + ); + } + (U512(result), overflow != 0) + }); + ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ + uint_overflowing_sub_reg!($name, $n_words, $self_expr, $other) + }) +} + +#[cfg(all(asm_available, target_arch="x86_64"))] +macro_rules! uint_overflowing_mul { + (U256, $n_words: expr, $self_expr: expr, $other: expr) => ({ + let mut result: [u64; 4] = unsafe { mem::uninitialized() }; + let self_t: &[u64; 4] = unsafe { &mem::transmute($self_expr) }; + let other_t: &[u64; 4] = unsafe { &mem::transmute($other) }; + + let overflow: u64; + unsafe { + asm!(" + mov $5, %rax + mulq $9 + mov %rax, $0 + mov %rdx, $1 + + mov $5, %rax + mulq $10 + add %rax, $1 + adc $$0, %rdx + mov %rdx, $2 + + mov $5, %rax + mulq $11 + add %rax, $2 + adc $$0, %rdx + mov %rdx, $3 + + mov $5, %rax + mulq $12 + add %rax, $3 + adc $$0, %rdx + mov %rdx, %rcx + + mov $6, %rax + mulq $9 + add %rax, $1 + adc %rdx, $2 + adc $$0, $3 + adc $$0, %rcx + + mov $6, %rax + mulq $10 + add %rax, $2 + adc %rdx, $3 + adc $$0, %rcx + adc $$0, $3 + adc $$0, %rcx + + mov $6, %rax + mulq $11 + add %rax, $3 + adc $$0, %rdx + or %rdx, %rcx + + mov $7, %rax + mulq $9 + add %rax, $2 + adc %rdx, $3 + adc $$0, %rcx + + mov $7, %rax + mulq $10 + add %rax, $3 + adc $$0, %rdx + or %rdx, %rcx + + mov $8, %rax + mulq $9 + add %rax, $3 + or %rdx, %rcx + + cmpq $$0, %rcx + jne 2f + + popcnt $8, %rcx + jrcxz 12f + + popcnt $12, %rcx + popcnt $11, %rax + add %rax, %rcx + popcnt $10, %rax + add %rax, %rcx + jmp 2f + + 12: + popcnt $12, %rcx + jrcxz 11f + + popcnt $7, %rcx + popcnt $6, %rax + add %rax, %rcx + + cmpq $$0, %rcx + jne 2f + + 11: + popcnt $11, %rcx + jrcxz 2f + popcnt $7, %rcx + + 2: + " + : /* $0 */ "={r8}"(result[0]), /* $1 */ "={r9}"(result[1]), /* $2 */ "={r10}"(result[2]), + /* $3 */ "={r11}"(result[3]), /* $4 */ "={rcx}"(overflow) + + : /* $5 */ "m"(self_t[0]), /* $6 */ "m"(self_t[1]), /* $7 */ "m"(self_t[2]), + /* $8 */ "m"(self_t[3]), /* $9 */ "m"(other_t[0]), /* $10 */ "m"(other_t[1]), + /* $11 */ "m"(other_t[2]), /* $12 */ "m"(other_t[3]) + : "rax", "rdx" + : + + ); + } + (U256(result), overflow > 0) + }); + ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ( + uint_overflowing_mul_reg!($name, $n_words, $self_expr, $other) + ) +} + +#[cfg(not(all(asm_available, target_arch="x86_64")))] +macro_rules! uint_overflowing_mul { + ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ + uint_overflowing_mul_reg!($name, $n_words, $self_expr, $other) + }) +} + +macro_rules! uint_overflowing_mul_reg { + ($name:ident, $n_words: expr, $self_expr: expr, $other: expr) => ({ + let $name(ref me) = $self_expr; + let $name(ref you) = $other; + let mut ret = [0u64; 2*$n_words]; + + for i in 0..$n_words { + if you[i] == 0 { + continue; + } + + let mut carry2 = 0u64; + let (b_u, b_l) = split(you[i]); + + for j in 0..$n_words { + if me[j] == 0 && carry2 == 0 { + continue; + } + + let a = split(me[j]); + + // multiply parts + let (c_l, overflow_l) = mul_u32(a, b_l, ret[i + j]); + let (c_u, overflow_u) = mul_u32(a, b_u, c_l >> 32); + ret[i + j] = (c_l & 0xFFFFFFFF) + (c_u << 32); + + // Only single overflow possible here + let carry = (c_u >> 32) + (overflow_u << 32) + overflow_l + carry2; + let (carry, o) = carry.overflowing_add(ret[i + j + 1]); + + ret[i + j + 1] = carry; + carry2 = o as u64; + } + } + + let mut res = [0u64; $n_words]; + let mut overflow = false; + for i in 0..$n_words { + res[i] = ret[i]; + } + + for i in $n_words..2*$n_words { + overflow |= ret[i] != 0; + } + + ($name(res), overflow) + }) +} + +macro_rules! overflowing { + ($op: expr, $overflow: expr) => ( + { + let (overflow_x, overflow_overflow) = $op; + $overflow |= overflow_overflow; + overflow_x + } + ); + ($op: expr) => ( + { + let (overflow_x, _overflow_overflow) = $op; + overflow_x + } + ); +} + +macro_rules! panic_on_overflow { + ($name: expr) => { + if $name { + panic!("arithmetic operation overflow") + } + } +} + +#[inline(always)] +fn mul_u32(a: (u64, u64), b: u64, carry: u64) -> (u64, u64) { + let upper = b * a.0; + let lower = b * a.1; + + let (res1, overflow1) = lower.overflowing_add(upper << 32); + let (res2, overflow2) = res1.overflowing_add(carry); + + let carry = (upper >> 32) + overflow1 as u64 + overflow2 as u64; + (res2, carry) +} + +#[inline(always)] +fn split(a: u64) -> (u64, u64) { + (a >> 32, a & 0xFFFFFFFF) +} + +/// Large, fixed-length unsigned integer type. +pub trait Uint: Sized + Default + FromStr + From + fmt::Debug + fmt::Display + PartialOrd + Ord + PartialEq + Eq + Hash { + + /// Returns new instance equalling zero. + 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; + /// Convert from a decimal string. + fn from_dec_str(value: &str) -> Result; + + /// Conversion to u32 + fn low_u32(&self) -> u32; + + /// Conversion to u64 + fn low_u64(&self) -> u64; + + /// Conversion to u32 with overflow checking + fn as_u32(&self) -> u32; + + /// Conversion to u64 with overflow checking + fn as_u64(&self) -> u64; + + /// Return the least number of bits needed to represent the number + fn bits(&self) -> usize; + /// Return if specific bit is set + fn bit(&self, index: usize) -> bool; + /// Return single byte + fn byte(&self, index: usize) -> u8; + /// Get this Uint as slice of bytes + fn to_bytes(&self, bytes: &mut[u8]); + + /// Create `Uint(10**n)` + fn exp10(n: usize) -> Self; + /// Return eponentation `self**other`. Panic on overflow. + fn pow(self, other: Self) -> Self; + /// Return wrapped eponentation `self**other` and flag if there was an overflow + fn overflowing_pow(self, other: Self) -> (Self, bool); + + /// Add this `Uint` to other returning result and possible overflow + fn overflowing_add(self, other: Self) -> (Self, bool); + + /// Subtract another `Uint` from this returning result and possible overflow + fn overflowing_sub(self, other: Self) -> (Self, bool); + + /// Multiple this `Uint` with other returning result and possible overflow + fn overflowing_mul(self, other: Self) -> (Self, bool); + + /// Divide this `Uint` by other returning result and possible overflow + fn overflowing_div(self, other: Self) -> (Self, bool); + + /// Returns reminder of division of this `Uint` by other and possible overflow + fn overflowing_rem(self, other: Self) -> (Self, bool); + + /// Returns negation of this `Uint` and overflow (always true) + fn overflowing_neg(self) -> (Self, bool); +} + +macro_rules! construct_uint { + ($name:ident, $n_words:expr) => ( + /// Little-endian large integer type + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct $name(pub [u64; $n_words]); + + impl Uint for $name { + type FromDecStrErr = FromHexError; + + /// TODO: optimize, throw appropriate err + fn from_dec_str(value: &str) -> Result { + Ok(value.bytes() + .map(|b| b - 48) + .fold($name::from(0u64), | acc, c | + // fast multiplication by 10 + // (acc << 3) + (acc << 1) => acc * 10 + (acc << 3) + (acc << 1) + $name::from(c) + )) + } + + #[inline] + fn low_u32(&self) -> u32 { + let &$name(ref arr) = self; + arr[0] as u32 + } + + #[inline] + fn low_u64(&self) -> u64 { + let &$name(ref arr) = self; + arr[0] + } + + /// Conversion to u32 with overflow checking + #[inline] + fn as_u32(&self) -> u32 { + let &$name(ref arr) = self; + if (arr[0] & (0xffffffffu64 << 32)) != 0 { + panic!("Integer overflow when casting U256") + } + self.as_u64() as u32 + } + + /// Conversion to u64 with overflow checking + #[inline] + fn as_u64(&self) -> u64 { + let &$name(ref arr) = self; + for i in 1..$n_words { + if arr[i] != 0 { + panic!("Integer overflow when casting U256") + } + } + arr[0] + } + + /// Return the least number of bits needed to represent the number + #[inline] + fn bits(&self) -> usize { + let &$name(ref arr) = self; + for i in 1..$n_words { + if arr[$n_words - i] > 0 { return (0x40 * ($n_words - i + 1)) - arr[$n_words - i].leading_zeros() as usize; } + } + 0x40 - arr[0].leading_zeros() as usize + } + + #[inline] + fn bit(&self, index: usize) -> bool { + let &$name(ref arr) = self; + arr[index / 64] & (1 << (index % 64)) != 0 + } + + #[inline] + fn byte(&self, index: usize) -> u8 { + let &$name(ref arr) = self; + (arr[index / 8] >> (((index % 8)) * 8)) as u8 + } + + fn to_bytes(&self, bytes: &mut[u8]) { + assert!($n_words * 8 == bytes.len()); + let &$name(ref arr) = self; + for i in 0..bytes.len() { + let rev = bytes.len() - 1 - i; + let pos = rev / 8; + bytes[i] = (arr[pos] >> ((rev % 8) * 8)) as u8; + } + } + + #[inline] + fn exp10(n: usize) -> Self { + match n { + 0 => Self::from(1u64), + _ => Self::exp10(n - 1) * Self::from(10u64) + } + } + + #[inline] + fn zero() -> Self { + From::from(0u64) + } + + #[inline] + fn one() -> Self { + 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 { + if expon == Self::zero() { + return Self::one() + } + let is_even = |x : &Self| x.low_u64() & 1 == 0; + + let u_one = Self::one(); + let u_two = Self::from(2); + let mut y = u_one; + let mut n = expon; + let mut x = self; + while n > u_one { + if is_even(&n) { + x = x * x; + n = n / u_two; + } else { + y = x * y; + x = x * x; + n = (n - u_one) / u_two; + } + } + x * y + } + + /// Fast exponentation by squaring + /// https://en.wikipedia.org/wiki/Exponentiation_by_squaring + fn overflowing_pow(self, expon: Self) -> (Self, bool) { + if expon == Self::zero() { + return (Self::one(), false) + } + let is_even = |x : &Self| x.low_u64() & 1 == 0; + + let u_one = Self::one(); + let u_two = Self::from(2); + let mut y = u_one; + let mut n = expon; + let mut x = self; + let mut overflow = false; + + while n > u_one { + if is_even(&n) { + x = overflowing!(x.overflowing_mul(x), overflow); + n = n / u_two; + } else { + y = overflowing!(x.overflowing_mul(y), overflow); + x = overflowing!(x.overflowing_mul(x), overflow); + n = (n - u_one) / u_two; + } + } + let res = overflowing!(x.overflowing_mul(y), overflow); + (res, overflow) + } + + /// Optimized instructions + #[inline(always)] + fn overflowing_add(self, other: $name) -> ($name, bool) { + uint_overflowing_add!($name, $n_words, self, other) + } + + #[inline(always)] + fn overflowing_sub(self, other: $name) -> ($name, bool) { + uint_overflowing_sub!($name, $n_words, self, other) + } + + #[inline(always)] + fn overflowing_mul(self, other: $name) -> ($name, bool) { + uint_overflowing_mul!($name, $n_words, self, other) + } + + fn overflowing_div(self, other: $name) -> ($name, bool) { + (self / other, false) + } + + fn overflowing_rem(self, other: $name) -> ($name, bool) { + (self % other, false) + } + + fn overflowing_neg(self) -> ($name, bool) { + (!self, true) + } + } + + impl $name { + #[allow(dead_code)] // not used when multiplied with inline assembly + /// Multiplication by u32 + fn mul_u32(self, other: u32) -> Self { + let (ret, overflow) = self.overflowing_mul_u32(other); + panic_on_overflow!(overflow); + ret + } + + #[allow(dead_code)] // not used when multiplied with inline assembly + /// Overflowing multiplication by u32 + fn overflowing_mul_u32(self, other: u32) -> (Self, bool) { + let $name(ref arr) = self; + let mut ret = [0u64; $n_words]; + let mut carry = 0; + let o = other as u64; + + for i in 0..$n_words { + let (res, carry2) = mul_u32(split(arr[i]), o, carry); + ret[i] = res; + carry = carry2; + } + + ($name(ret), carry > 0) + } + } + + impl Default for $name { + fn default() -> Self { + $name::zero() + } + } + + impl serde::Serialize for $name { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where S: serde::Serializer { + let mut hex = "0x".to_owned(); + let mut bytes = [0u8; 8 * $n_words]; + self.to_bytes(&mut bytes); + let len = cmp::max((self.bits() + 7) / 8, 1); + hex.push_str(bytes[bytes.len() - len..].to_hex().as_ref()); + serializer.serialize_str(hex.as_ref()) + } + } + + impl serde::Deserialize for $name { + fn deserialize(deserializer: &mut D) -> Result<$name, D::Error> + where D: serde::Deserializer { + struct UintVisitor; + + impl serde::de::Visitor for UintVisitor { + type Value = $name; + + fn visit_str(&mut self, value: &str) -> Result where E: serde::Error { + // 0x + len + if value.len() > 2 + $n_words * 16 { + return Err(serde::Error::custom("Invalid length.")); + } + + $name::from_str(&value[2..]).map_err(|_| serde::Error::custom("Invalid hex value.")) + } + + fn visit_string(&mut self, value: String) -> Result where E: serde::Error { + self.visit_str(value.as_ref()) + } + } + + deserializer.deserialize(UintVisitor) + } + } + + impl From for $name { + fn from(value: u64) -> $name { + let mut ret = [0; $n_words]; + ret[0] = value; + $name(ret) + } + } + + + impl_map_from!($name, u8, u64); + impl_map_from!($name, u16, u64); + impl_map_from!($name, u32, u64); + impl_map_from!($name, usize, u64); + + impl From for $name { + fn from(value: i64) -> $name { + match value >= 0 { + true => From::from(value as u64), + false => { panic!("Unsigned integer can't be created from negative value"); } + } + } + } + + impl_map_from!($name, i8, i64); + impl_map_from!($name, i16, i64); + impl_map_from!($name, i32, i64); + impl_map_from!($name, isize, i64); + + impl<'a> From<&'a [u8]> for $name { + fn from(bytes: &[u8]) -> $name { + assert!($n_words * 8 >= bytes.len()); + + let mut ret = [0; $n_words]; + for i in 0..bytes.len() { + let rev = bytes.len() - 1 - i; + let pos = rev / 8; + ret[pos] += (bytes[i] as u64) << ((rev % 8) * 8); + } + $name(ret) + } + } + + impl FromStr for $name { + type Err = FromHexError; + + fn from_str(value: &str) -> Result<$name, Self::Err> { + let bytes: Vec = match value.len() % 2 == 0 { + true => try!(value.from_hex()), + false => try!(("0".to_owned() + value).from_hex()) + }; + + let bytes_ref: &[u8] = &bytes; + Ok(From::from(bytes_ref)) + } + } + + impl Add<$name> for $name { + type Output = $name; + + fn add(self, other: $name) -> $name { + let (result, overflow) = self.overflowing_add(other); + panic_on_overflow!(overflow); + result + } + } + + impl Sub<$name> for $name { + type Output = $name; + + #[inline] + fn sub(self, other: $name) -> $name { + let (result, overflow) = self.overflowing_sub(other); + panic_on_overflow!(overflow); + result + } + } + + impl Mul<$name> for $name { + type Output = $name; + + fn mul(self, other: $name) -> $name { + let (result, overflow) = self.overflowing_mul(other); + panic_on_overflow!(overflow); + result + } + } + + impl Div<$name> for $name { + type Output = $name; + + fn div(self, other: $name) -> $name { + let mut sub_copy = self; + let mut shift_copy = other; + let mut ret = [0u64; $n_words]; + + let my_bits = self.bits(); + let your_bits = other.bits(); + + // Check for division by 0 + assert!(your_bits != 0); + + // Early return in case we are dividing by a larger number than us + if my_bits < your_bits { + return $name(ret); + } + + // Bitwise long division + let mut shift = my_bits - your_bits; + shift_copy = shift_copy << shift; + loop { + if sub_copy >= shift_copy { + ret[shift / 64] |= 1 << (shift % 64); + sub_copy = overflowing!(sub_copy.overflowing_sub(shift_copy)); + } + shift_copy = shift_copy >> 1; + if shift == 0 { break; } + shift -= 1; + } + + $name(ret) + } + } + + impl Rem<$name> for $name { + type Output = $name; + + fn rem(self, other: $name) -> $name { + let times = self / other; + self - (times * other) + } + } + + // TODO: optimise and traitify. + + impl BitAnd<$name> for $name { + type Output = $name; + + #[inline] + fn bitand(self, other: $name) -> $name { + let $name(ref arr1) = self; + let $name(ref arr2) = other; + let mut ret = [0u64; $n_words]; + for i in 0..$n_words { + ret[i] = arr1[i] & arr2[i]; + } + $name(ret) + } + } + + impl BitXor<$name> for $name { + type Output = $name; + + #[inline] + fn bitxor(self, other: $name) -> $name { + let $name(ref arr1) = self; + let $name(ref arr2) = other; + let mut ret = [0u64; $n_words]; + for i in 0..$n_words { + ret[i] = arr1[i] ^ arr2[i]; + } + $name(ret) + } + } + + impl BitOr<$name> for $name { + type Output = $name; + + #[inline] + fn bitor(self, other: $name) -> $name { + let $name(ref arr1) = self; + let $name(ref arr2) = other; + let mut ret = [0u64; $n_words]; + for i in 0..$n_words { + ret[i] = arr1[i] | arr2[i]; + } + $name(ret) + } + } + + impl Not for $name { + type Output = $name; + + #[inline] + fn not(self) -> $name { + let $name(ref arr) = self; + let mut ret = [0u64; $n_words]; + for i in 0..$n_words { + ret[i] = !arr[i]; + } + $name(ret) + } + } + + impl Shl for $name { + type Output = $name; + + fn shl(self, shift: usize) -> $name { + let $name(ref original) = self; + let mut ret = [0u64; $n_words]; + let word_shift = shift / 64; + let bit_shift = shift % 64; + + // shift + for i in word_shift..$n_words { + ret[i] += original[i - word_shift] << bit_shift; + } + // carry + if bit_shift > 0 { + for i in word_shift+1..$n_words { + ret[i] += original[i - 1 - word_shift] >> (64 - bit_shift); + } + } + $name(ret) + } + } + + impl Shr for $name { + type Output = $name; + + fn shr(self, shift: usize) -> $name { + let $name(ref original) = self; + let mut ret = [0u64; $n_words]; + let word_shift = shift / 64; + let bit_shift = shift % 64; + + for i in word_shift..$n_words { + // Shift + ret[i - word_shift] += original[i] >> bit_shift; + // Carry + if bit_shift > 0 && i < $n_words - 1 { + ret[i - word_shift] += original[i + 1] << (64 - bit_shift); + } + } + $name(ret) + } + } + + impl Ord for $name { + fn cmp(&self, other: &$name) -> Ordering { + let &$name(ref me) = self; + let &$name(ref you) = other; + let mut i = $n_words; + while i > 0 { + i -= 1; + if me[i] < you[i] { return Ordering::Less; } + if me[i] > you[i] { return Ordering::Greater; } + } + Ordering::Equal + } + } + + impl PartialOrd for $name { + fn partial_cmp(&self, other: &$name) -> Option { + Some(self.cmp(other)) + } + } + + impl fmt::Debug for $name { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, f) + } + } + + impl fmt::Display for $name { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if *self == $name::zero() { + return write!(f, "0"); + } + + let mut s = String::new(); + let mut current = *self; + let ten = $name::from(10); + + while current != $name::zero() { + s = format!("{}{}", (current % ten).low_u32(), s); + current = current / ten; + } + + write!(f, "{}", s) + } + } + + impl fmt::LowerHex for $name { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let &$name(ref data) = self; + try!(write!(f, "0x")); + let mut latch = false; + for ch in data.iter().rev() { + for x in 0..16 { + let nibble = (ch & (15u64 << ((15 - x) * 4) as u64)) >> (((15 - x) * 4) as u64); + if !latch { latch = nibble != 0 } + if latch { + try!(write!(f, "{:x}", nibble)); + } + } + } + Ok(()) + } + } + + #[cfg_attr(feature="dev", allow(derive_hash_xor_eq))] // We are pretty sure it's ok. + impl Hash for $name { + fn hash(&self, state: &mut H) where H: Hasher { + unsafe { state.write(::std::slice::from_raw_parts(self.0.as_ptr() as *mut u8, self.0.len() * 8)); } + state.finish(); + } + } + ); +} + +construct_uint!(U512, 8); +construct_uint!(U256, 4); +construct_uint!(U128, 2); + +impl U256 { + /// Multiplies two 256-bit integers to produce full 512-bit integer + /// No overflow possible + #[cfg(all(asm_available, target_arch="x86_64"))] + pub fn full_mul(self, other: U256) -> U512 { + let self_t: &[u64; 4] = unsafe { &mem::transmute(self) }; + let other_t: &[u64; 4] = unsafe { &mem::transmute(other) }; + let mut result: [u64; 8] = unsafe { mem::uninitialized() }; + unsafe { + asm!(" + mov $8, %rax + mulq $12 + mov %rax, $0 + mov %rdx, $1 + + mov $8, %rax + mulq $13 + add %rax, $1 + adc $$0, %rdx + mov %rdx, $2 + + mov $8, %rax + mulq $14 + add %rax, $2 + adc $$0, %rdx + mov %rdx, $3 + + mov $8, %rax + mulq $15 + add %rax, $3 + adc $$0, %rdx + mov %rdx, $4 + + mov $9, %rax + mulq $12 + add %rax, $1 + adc %rdx, $2 + adc $$0, $3 + adc $$0, $4 + xor $5, $5 + adc $$0, $5 + xor $6, $6 + adc $$0, $6 + xor $7, $7 + adc $$0, $7 + + mov $9, %rax + mulq $13 + add %rax, $2 + adc %rdx, $3 + adc $$0, $4 + adc $$0, $5 + adc $$0, $6 + adc $$0, $7 + + mov $9, %rax + mulq $14 + add %rax, $3 + adc %rdx, $4 + adc $$0, $5 + adc $$0, $6 + adc $$0, $7 + + mov $9, %rax + mulq $15 + add %rax, $4 + adc %rdx, $5 + adc $$0, $6 + adc $$0, $7 + + mov $10, %rax + mulq $12 + add %rax, $2 + adc %rdx, $3 + adc $$0, $4 + adc $$0, $5 + adc $$0, $6 + adc $$0, $7 + + mov $10, %rax + mulq $13 + add %rax, $3 + adc %rdx, $4 + adc $$0, $5 + adc $$0, $6 + adc $$0, $7 + + mov $10, %rax + mulq $14 + add %rax, $4 + adc %rdx, $5 + adc $$0, $6 + adc $$0, $7 + + mov $10, %rax + mulq $15 + add %rax, $5 + adc %rdx, $6 + adc $$0, $7 + + mov $11, %rax + mulq $12 + add %rax, $3 + adc %rdx, $4 + adc $$0, $5 + adc $$0, $6 + adc $$0, $7 + + mov $11, %rax + mulq $13 + add %rax, $4 + adc %rdx, $5 + adc $$0, $6 + adc $$0, $7 + + mov $11, %rax + mulq $14 + add %rax, $5 + adc %rdx, $6 + adc $$0, $7 + + mov $11, %rax + mulq $15 + add %rax, $6 + adc %rdx, $7 + " + : /* $0 */ "={r8}"(result[0]), /* $1 */ "={r9}"(result[1]), /* $2 */ "={r10}"(result[2]), + /* $3 */ "={r11}"(result[3]), /* $4 */ "={r12}"(result[4]), /* $5 */ "={r13}"(result[5]), + /* $6 */ "={r14}"(result[6]), /* $7 */ "={r15}"(result[7]) + + : /* $8 */ "m"(self_t[0]), /* $9 */ "m"(self_t[1]), /* $10 */ "m"(self_t[2]), + /* $11 */ "m"(self_t[3]), /* $12 */ "m"(other_t[0]), /* $13 */ "m"(other_t[1]), + /* $14 */ "m"(other_t[2]), /* $15 */ "m"(other_t[3]) + : "rax", "rdx" + : + ); + } + U512(result) + } + + /// Multiplies two 256-bit integers to produce full 512-bit integer + /// No overflow possible + #[cfg(not(all(asm_available, target_arch="x86_64")))] + pub fn full_mul(self, other: U256) -> U512 { + let U256(ref me) = self; + let U256(ref you) = other; + let mut ret = [0u64; 8]; + + for i in 0..4 { + if you[i] == 0 { + continue; + } + + let mut carry2 = 0u64; + let (b_u, b_l) = split(you[i]); + + for j in 0..4 { + if me[j] == 0 && carry2 == 0 { + continue; + } + + let a = split(me[j]); + + // multiply parts + let (c_l, overflow_l) = mul_u32(a, b_l, ret[i + j]); + let (c_u, overflow_u) = mul_u32(a, b_u, c_l >> 32); + ret[i + j] = (c_l & 0xFFFFFFFF) + (c_u << 32); + + // Only single overflow possible here + let carry = (c_u >> 32) + (overflow_u << 32) + overflow_l + carry2; + let (carry, o) = carry.overflowing_add(ret[i + j + 1]); + + ret[i + j + 1] = carry; + carry2 = o as u64; + } + } + + U512(ret) + } +} + +impl From for U512 { + fn from(value: U256) -> U512 { + let U256(ref arr) = value; + let mut ret = [0; 8]; + ret[0] = arr[0]; + ret[1] = arr[1]; + ret[2] = arr[2]; + ret[3] = arr[3]; + U512(ret) + } +} + +impl From for U256 { + fn from(value: U512) -> U256 { + let U512(ref arr) = value; + if arr[4] | arr[5] | arr[6] | arr[7] != 0 { + panic!("Overflow"); + } + let mut ret = [0; 4]; + ret[0] = arr[0]; + ret[1] = arr[1]; + ret[2] = arr[2]; + ret[3] = arr[3]; + U256(ret) + } +} + +impl<'a> From<&'a U256> for U512 { + fn from(value: &'a U256) -> U512 { + let U256(ref arr) = *value; + let mut ret = [0; 8]; + ret[0] = arr[0]; + ret[1] = arr[1]; + ret[2] = arr[2]; + ret[3] = arr[3]; + U512(ret) + } +} + +impl<'a> From<&'a U512> for U256 { + fn from(value: &'a U512) -> U256 { + let U512(ref arr) = *value; + if arr[4] | arr[5] | arr[6] | arr[7] != 0 { + panic!("Overflow"); + } + let mut ret = [0; 4]; + ret[0] = arr[0]; + ret[1] = arr[1]; + ret[2] = arr[2]; + ret[3] = arr[3]; + U256(ret) + } +} + +impl From for U128 { + fn from(value: U256) -> U128 { + let U256(ref arr) = value; + if arr[2] | arr[3] != 0 { + panic!("Overflow"); + } + let mut ret = [0; 2]; + ret[0] = arr[0]; + ret[1] = arr[1]; + U128(ret) + } +} + +impl From for U128 { + fn from(value: U512) -> U128 { + let U512(ref arr) = value; + if arr[2] | arr[3] | arr[4] | arr[5] | arr[6] | arr[7] != 0 { + panic!("Overflow"); + } + let mut ret = [0; 2]; + ret[0] = arr[0]; + ret[1] = arr[1]; + U128(ret) + } +} + +impl From for U512 { + fn from(value: U128) -> U512 { + let U128(ref arr) = value; + let mut ret = [0; 8]; + ret[0] = arr[0]; + ret[1] = arr[1]; + U512(ret) + } +} + +impl From for U256 { + fn from(value: U128) -> U256 { + let U128(ref arr) = value; + let mut ret = [0; 4]; + ret[0] = arr[0]; + ret[1] = arr[1]; + U256(ret) + } +} + +impl From for u64 { + fn from(value: U256) -> u64 { + value.as_u64() + } +} + +impl From for u32 { + fn from(value: U256) -> u32 { + value.as_u32() + } +} + +/// Constant value of `U256::zero()` that can be used for a reference saving an additional instance creation. +pub const ZERO_U256: U256 = U256([0x00u64; 4]); +/// Constant value of `U256::one()` that can be used for a reference saving an additional instance creation. +pub const ONE_U256: U256 = U256([0x01u64, 0x00u64, 0x00u64, 0x00u64]); + + +known_heap_size!(0, U128, U256); + +#[cfg(test)] +mod tests { + use uint::{Uint, U128, U256, U512}; + use std::str::FromStr; + + #[test] + pub fn uint256_from() { + let e = U256([10, 0, 0, 0]); + + // test unsigned initialization + let ua = U256::from(10u8); + let ub = U256::from(10u16); + let uc = U256::from(10u32); + let ud = U256::from(10u64); + assert_eq!(e, ua); + assert_eq!(e, ub); + assert_eq!(e, uc); + assert_eq!(e, ud); + + // test initialization from bytes + let va = U256::from(&[10u8][..]); + assert_eq!(e, va); + + // more tests for initialization from bytes + assert_eq!(U256([0x1010, 0, 0, 0]), U256::from(&[0x10u8, 0x10][..])); + assert_eq!(U256([0x12f0, 0, 0, 0]), U256::from(&[0x12u8, 0xf0][..])); + assert_eq!(U256([0x12f0, 0, 0, 0]), U256::from(&[0, 0x12u8, 0xf0][..])); + assert_eq!(U256([0x12f0, 0 , 0, 0]), U256::from(&[0, 0, 0, 0, 0, 0, 0, 0x12u8, 0xf0][..])); + assert_eq!(U256([0x12f0, 1 , 0, 0]), U256::from(&[1, 0, 0, 0, 0, 0, 0, 0x12u8, 0xf0][..])); + assert_eq!(U256([0x12f0, 1 , 0x0910203040506077, 0x8090a0b0c0d0e0f0]), U256::from(&[ + 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, + 0x09, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x77, + 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0x12u8, 0xf0][..])); + assert_eq!(U256([0x00192437100019fa, 0x243710, 0, 0]), U256::from(&[ + 0x24u8, 0x37, 0x10, + 0, 0x19, 0x24, 0x37, 0x10, 0, 0x19, 0xfa][..])); + + // test initializtion from string + let sa = U256::from_str("0a").unwrap(); + assert_eq!(e, sa); + assert_eq!(U256([0x1010, 0, 0, 0]), U256::from_str("1010").unwrap()); + assert_eq!(U256([0x12f0, 0, 0, 0]), U256::from_str("12f0").unwrap()); + assert_eq!(U256([0x12f0, 0, 0, 0]), U256::from_str("12f0").unwrap()); + assert_eq!(U256([0x12f0, 0 , 0, 0]), U256::from_str("0000000012f0").unwrap()); + assert_eq!(U256([0x12f0, 1 , 0, 0]), U256::from_str("0100000000000012f0").unwrap()); + assert_eq!(U256([0x12f0, 1 , 0x0910203040506077, 0x8090a0b0c0d0e0f0]), U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0").unwrap()); + } + + #[test] + pub fn uint256_to() { + let hex = "8090a0b0c0d0e0f00910203040506077583a2cf8264910e1436bda32571012f0"; + let uint = U256::from_str(hex).unwrap(); + let mut bytes = [0u8; 32]; + uint.to_bytes(&mut bytes); + let uint2 = U256::from(&bytes[..]); + assert_eq!(uint, uint2); + } + + #[test] + pub fn uint256_bits_test() { + assert_eq!(U256::from(0u64).bits(), 0); + assert_eq!(U256::from(255u64).bits(), 8); + assert_eq!(U256::from(256u64).bits(), 9); + assert_eq!(U256::from(300u64).bits(), 9); + assert_eq!(U256::from(60000u64).bits(), 16); + assert_eq!(U256::from(70000u64).bits(), 17); + + //// Try to read the following lines out loud quickly + let mut shl = U256::from(70000u64); + shl = shl << 100; + assert_eq!(shl.bits(), 117); + shl = shl << 100; + assert_eq!(shl.bits(), 217); + shl = shl << 100; + assert_eq!(shl.bits(), 0); + + //// Bit set check + //// 01010 + assert!(!U256::from(10u8).bit(0)); + assert!(U256::from(10u8).bit(1)); + assert!(!U256::from(10u8).bit(2)); + assert!(U256::from(10u8).bit(3)); + assert!(!U256::from(10u8).bit(4)); + + //// byte check + assert_eq!(U256::from(10u8).byte(0), 10); + assert_eq!(U256::from(0xffu64).byte(0), 0xff); + assert_eq!(U256::from(0xffu64).byte(1), 0); + assert_eq!(U256::from(0x01ffu64).byte(0), 0xff); + assert_eq!(U256::from(0x01ffu64).byte(1), 0x1); + assert_eq!(U256([0u64, 0xfc, 0, 0]).byte(8), 0xfc); + assert_eq!(U256([0u64, 0, 0, u64::max_value()]).byte(31), 0xff); + assert_eq!(U256([0u64, 0, 0, (u64::max_value() >> 8) + 1]).byte(31), 0x01); + } + + #[test] + #[cfg_attr(feature="dev", allow(eq_op))] + pub fn uint256_comp_test() { + let small = U256([10u64, 0, 0, 0]); + let big = U256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0]); + let bigger = U256([0x9C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0]); + let biggest = U256([0x5C8C3EE70C644118u64, 0x0209E7378231E632, 0, 1]); + + assert!(small < big); + assert!(big < bigger); + assert!(bigger < biggest); + assert!(bigger <= biggest); + assert!(biggest <= biggest); + assert!(bigger >= big); + assert!(bigger >= small); + assert!(small <= small); + } + + #[test] + pub fn uint256_arithmetic_test() { + let init = U256::from(0xDEADBEEFDEADBEEFu64); + let copy = init; + + let add = init + copy; + assert_eq!(add, U256([0xBD5B7DDFBD5B7DDEu64, 1, 0, 0])); + // Bitshifts + let shl = add << 88; + assert_eq!(shl, U256([0u64, 0xDFBD5B7DDE000000, 0x1BD5B7D, 0])); + let shr = shl >> 40; + assert_eq!(shr, U256([0x7DDE000000000000u64, 0x0001BD5B7DDFBD5B, 0, 0])); + // Increment + let incr = shr + U256::from(1u64); + assert_eq!(incr, U256([0x7DDE000000000001u64, 0x0001BD5B7DDFBD5B, 0, 0])); + // Subtraction + let sub = overflowing!(incr.overflowing_sub(init)); + assert_eq!(sub, U256([0x9F30411021524112u64, 0x0001BD5B7DDFBD5A, 0, 0])); + // Multiplication + let mult = sub.mul_u32(300); + assert_eq!(mult, U256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0])); + // Division + assert_eq!(U256::from(105u8) / U256::from(5u8), U256::from(21u8)); + let div = mult / U256::from(300u16); + assert_eq!(div, U256([0x9F30411021524112u64, 0x0001BD5B7DDFBD5A, 0, 0])); + //// TODO: bit inversion + } + + #[test] + pub fn uint256_simple_mul() { + let a = U256::from_str("10000000000000000").unwrap(); + let b = U256::from_str("10000000000000000").unwrap(); + + let c = U256::from_str("100000000000000000000000000000000").unwrap(); + println!("Multiplying"); + let result = a.overflowing_mul(b); + println!("Got result"); + assert_eq!(result, (c, false)) + } + + #[test] + pub fn uint256_extreme_bitshift_test() { + //// Shifting a u64 by 64 bits gives an undefined value, so make sure that + //// we're doing the Right Thing here + let init = U256::from(0xDEADBEEFDEADBEEFu64); + + assert_eq!(init << 64, U256([0, 0xDEADBEEFDEADBEEF, 0, 0])); + let add = (init << 64) + init; + assert_eq!(add, U256([0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0, 0])); + assert_eq!(add >> 0, U256([0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0, 0])); + assert_eq!(add << 0, U256([0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0, 0])); + assert_eq!(add >> 64, U256([0xDEADBEEFDEADBEEF, 0, 0, 0])); + assert_eq!(add << 64, U256([0, 0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0])); + } + + #[test] + pub fn uint256_exp10() { + assert_eq!(U256::exp10(0), U256::from(1u64)); + println!("\none: {:?}", U256::from(1u64)); + println!("ten: {:?}", U256::from(10u64)); + assert_eq!(U256::from(2u64) * U256::from(10u64), U256::from(20u64)); + assert_eq!(U256::exp10(1), U256::from(10u64)); + assert_eq!(U256::exp10(2), U256::from(100u64)); + assert_eq!(U256::exp10(5), U256::from(100000u64)); + } + + #[test] + pub fn uint256_mul32() { + assert_eq!(U256::from(0u64).mul_u32(2), U256::from(0u64)); + assert_eq!(U256::from(1u64).mul_u32(2), U256::from(2u64)); + assert_eq!(U256::from(10u64).mul_u32(2), U256::from(20u64)); + assert_eq!(U256::from(10u64).mul_u32(5), U256::from(50u64)); + assert_eq!(U256::from(1000u64).mul_u32(50), U256::from(50000u64)); + } + + #[test] + fn uint256_pow () { + assert_eq!(U256::from(10).pow(U256::from(0)), U256::from(1)); + assert_eq!(U256::from(10).pow(U256::from(1)), U256::from(10)); + assert_eq!(U256::from(10).pow(U256::from(2)), U256::from(100)); + assert_eq!(U256::from(10).pow(U256::from(3)), U256::from(1000)); + assert_eq!(U256::from(10).pow(U256::from(20)), U256::exp10(20)); + } + + #[test] + #[should_panic] + fn uint256_pow_overflow_panic () { + U256::from(2).pow(U256::from(0x100)); + } + + #[test] + fn uint256_overflowing_pow () { + // assert_eq!( + // U256::from(2).overflowing_pow(U256::from(0xff)), + // (U256::from_str("8000000000000000000000000000000000000000000000000000000000000000").unwrap(), false) + // ); + assert_eq!( + U256::from(2).overflowing_pow(U256::from(0x100)), + (U256::zero(), true) + ); + } + + #[test] + pub fn uint256_mul1() { + assert_eq!(U256::from(1u64) * U256::from(10u64), U256::from(10u64)); + } + + #[test] + pub fn uint256_mul2() { + let a = U512::from_str("10000000000000000fffffffffffffffe").unwrap(); + let b = U512::from_str("ffffffffffffffffffffffffffffffff").unwrap(); + + assert_eq!(a * b, U512::from_str("10000000000000000fffffffffffffffcffffffffffffffff0000000000000002").unwrap()); + } + + #[test] + pub fn uint256_overflowing_mul() { + assert_eq!( + U256::from_str("100000000000000000000000000000000").unwrap().overflowing_mul( + U256::from_str("100000000000000000000000000000000").unwrap() + ), + (U256::zero(), true) + ); + } + + #[test] + pub fn uint128_add() { + assert_eq!( + U128::from_str("fffffffffffffffff").unwrap() + U128::from_str("fffffffffffffffff").unwrap(), + U128::from_str("1ffffffffffffffffe").unwrap() + ); + } + + #[test] + pub fn uint128_add_overflow() { + assert_eq!( + U128::from_str("ffffffffffffffffffffffffffffffff").unwrap() + .overflowing_add( + U128::from_str("ffffffffffffffffffffffffffffffff").unwrap() + ), + (U128::from_str("fffffffffffffffffffffffffffffffe").unwrap(), true) + ); + } + + #[test] + #[should_panic] + // overflows panic only in debug builds. Running this test with `--release` flag, always fails + #[ignore] + pub fn uint128_add_overflow_panic() { + U128::from_str("ffffffffffffffffffffffffffffffff").unwrap() + + + U128::from_str("ffffffffffffffffffffffffffffffff").unwrap(); + } + + #[test] + pub fn uint128_mul() { + assert_eq!( + U128::from_str("fffffffff").unwrap() * U128::from_str("fffffffff").unwrap(), + U128::from_str("ffffffffe000000001").unwrap()); + } + + #[test] + pub fn uint512_mul() { + assert_eq!( + U512::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() + * + U512::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(), + U512::from_str("3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000001").unwrap() + ); + } + + #[test] + pub fn uint256_mul_overflow() { + assert_eq!( + U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() + .overflowing_mul( + U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() + ), + (U256::from_str("1").unwrap(), true) + ); + } + + #[test] + #[should_panic] + pub fn uint256_mul_overflow_panic() { + U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() + * + U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(); + } + + #[test] + pub fn uint256_sub_overflow() { + assert_eq!( + U256::from_str("0").unwrap() + .overflowing_sub( + U256::from_str("1").unwrap() + ), + (U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(), true) + ); + } + + #[test] + #[should_panic] + pub fn uint256_sub_overflow_panic() { + U256::from_str("0").unwrap() + - + U256::from_str("1").unwrap(); + } + + #[test] + pub fn uint256_shl() { + assert_eq!( + U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() + << 4, + U256::from_str("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0").unwrap() + ); + } + + #[test] + pub fn uint256_shl_words() { + assert_eq!( + U256::from_str("0000000000000001ffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() + << 64, + U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000").unwrap() + ); + assert_eq!( + U256::from_str("0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() + << 64, + U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000").unwrap() + ); + } + + #[test] + pub fn uint256_mul() { + assert_eq!( + U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() + * + U256::from_str("2").unwrap(), + U256::from_str("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe").unwrap() + ); + } + + #[test] + fn uint256_div() { + assert_eq!(U256::from(10u64) / U256::from(1u64), U256::from(10u64)); + assert_eq!(U256::from(10u64) / U256::from(2u64), U256::from(5u64)); + assert_eq!(U256::from(10u64) / U256::from(3u64), U256::from(3u64)); + } + + #[test] + fn uint256_rem() { + assert_eq!(U256::from(10u64) % U256::from(1u64), U256::from(0u64)); + assert_eq!(U256::from(10u64) % U256::from(3u64), U256::from(1u64)); + } + + #[test] + fn uint256_from_dec_str() { + assert_eq!(U256::from_dec_str("10").unwrap(), U256::from(10u64)); + assert_eq!(U256::from_dec_str("1024").unwrap(), U256::from(1024u64)); + } + + #[test] + fn display_uint() { + let s = "12345678987654321023456789"; + assert_eq!(format!("{}", U256::from_dec_str(s).unwrap()), s); + } + + #[test] + fn display_uint_zero() { + assert_eq!(format!("{}", U256::from(0)), "0"); + } + + #[test] + fn u512_multi_adds() { + let (result, _) = U512([0, 0, 0, 0, 0, 0, 0, 0]).overflowing_add(U512([0, 0, 0, 0, 0, 0, 0, 0])); + assert_eq!(result, U512([0, 0, 0, 0, 0, 0, 0, 0])); + + let (result, _) = U512([1, 0, 0, 0, 0, 0, 0, 1]).overflowing_add(U512([1, 0, 0, 0, 0, 0, 0, 1])); + assert_eq!(result, U512([2, 0, 0, 0, 0, 0, 0, 2])); + + let (result, _) = U512([0, 0, 0, 0, 0, 0, 0, 1]).overflowing_add(U512([0, 0, 0, 0, 0, 0, 0, 1])); + assert_eq!(result, U512([0, 0, 0, 0, 0, 0, 0, 2])); + + let (result, _) = U512([0, 0, 0, 0, 0, 0, 2, 1]).overflowing_add(U512([0, 0, 0, 0, 0, 0, 3, 1])); + assert_eq!(result, U512([0, 0, 0, 0, 0, 0, 5, 2])); + + let (result, _) = U512([1, 2, 3, 4, 5, 6, 7, 8]).overflowing_add(U512([9, 10, 11, 12, 13, 14, 15, 16])); + assert_eq!(result, U512([10, 12, 14, 16, 18, 20, 22, 24])); + + let (_, overflow) = U512([0, 0, 0, 0, 0, 0, 2, 1]).overflowing_add(U512([0, 0, 0, 0, 0, 0, 3, 1])); + assert!(!overflow); + + let (_, overflow) = U512([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_add(U512([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert!(overflow); + + let (_, overflow) = U512([0, 0, 0, 0, 0, 0, 0, ::std::u64::MAX]) + .overflowing_add(U512([0, 0, 0, 0, 0, 0, 0, ::std::u64::MAX])); + assert!(overflow); + + let (_, overflow) = U512([0, 0, 0, 0, 0, 0, 0, ::std::u64::MAX]) + .overflowing_add(U512([0, 0, 0, 0, 0, 0, 0, 0])); + assert!(!overflow); + } + + #[test] + fn u256_multi_adds() { + let (result, _) = U256([0, 0, 0, 0]).overflowing_add(U256([0, 0, 0, 0])); + assert_eq!(result, U256([0, 0, 0, 0])); + + let (result, _) = U256([0, 0, 0, 1]).overflowing_add(U256([0, 0, 0, 1])); + assert_eq!(result, U256([0, 0, 0, 2])); + + let (result, overflow) = U256([0, 0, 2, 1]).overflowing_add(U256([0, 0, 3, 1])); + assert_eq!(result, U256([0, 0, 5, 2])); + assert!(!overflow); + + let (_, overflow) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_add(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert!(overflow); + + let (_, overflow) = U256([0, 0, 0, ::std::u64::MAX]).overflowing_add(U256([0, 0, 0, ::std::u64::MAX])); + assert!(overflow); + } + + + #[test] + fn u256_multi_subs() { + let (result, _) = U256([0, 0, 0, 0]).overflowing_sub(U256([0, 0, 0, 0])); + assert_eq!(result, U256([0, 0, 0, 0])); + + let (result, _) = U256([0, 0, 0, 1]).overflowing_sub(U256([0, 0, 0, 1])); + assert_eq!(result, U256([0, 0, 0, 0])); + + let (_, overflow) = U256([0, 0, 2, 1]).overflowing_sub(U256([0, 0, 3, 1])); + assert!(overflow); + + let (result, overflow) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_sub(U256([::std::u64::MAX/2, ::std::u64::MAX/2, ::std::u64::MAX/2, ::std::u64::MAX/2])); + assert!(!overflow); + assert_eq!(U256([::std::u64::MAX/2+1, ::std::u64::MAX/2+1, ::std::u64::MAX/2+1, ::std::u64::MAX/2+1]), result); + + let (result, overflow) = U256([0, 0, 0, 1]).overflowing_sub(U256([0, 0, 1, 0])); + assert!(!overflow); + assert_eq!(U256([0, 0, ::std::u64::MAX, 0]), result); + + let (result, overflow) = U256([0, 0, 0, 1]).overflowing_sub(U256([1, 0, 0, 0])); + assert!(!overflow); + assert_eq!(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]), result); + } + + #[test] + fn u512_multi_subs() { + let (result, _) = U512([0, 0, 0, 0, 0, 0, 0, 0]).overflowing_sub(U512([0, 0, 0, 0, 0, 0, 0, 0])); + assert_eq!(result, U512([0, 0, 0, 0, 0, 0, 0, 0])); + + let (result, _) = U512([10, 9, 8, 7, 6, 5, 4, 3]).overflowing_sub(U512([9, 8, 7, 6, 5, 4, 3, 2])); + assert_eq!(result, U512([1, 1, 1, 1, 1, 1, 1, 1])); + + let (_, overflow) = U512([10, 9, 8, 7, 6, 5, 4, 3]).overflowing_sub(U512([9, 8, 7, 6, 5, 4, 3, 2])); + assert!(!overflow); + + let (_, overflow) = U512([9, 8, 7, 6, 5, 4, 3, 2]).overflowing_sub(U512([10, 9, 8, 7, 6, 5, 4, 3])); + assert!(overflow); + } + + #[test] + fn u256_multi_carry_all() { + let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U256([1, ::std::u64::MAX-1, 0, 0]), result); + + let (result, _) = U256([0, ::std::u64::MAX, 0, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U256([0, 1, ::std::u64::MAX-1, 0]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX-1, 0]), result); + + let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX-1, 0]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); + assert_eq!(U256([1, 0, ::std::u64::MAX-1, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]).overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1]), result); + + let (result, _) = U256([::std::u64::MAX, 0, 0, 0]).overflowing_mul( + U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U256([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); + assert_eq!(U256([1, 0, ::std::u64::MAX, ::std::u64::MAX-1]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); + assert_eq!(U256([1, 0, ::std::u64::MAX, ::std::u64::MAX-1]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); + assert_eq!(U256([1, 0, ::std::u64::MAX, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert_eq!(U256([1, 0, ::std::u64::MAX, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); + assert_eq!(U256([1, 0, 0, ::std::u64::MAX-1]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert_eq!(U256([1, 0, 0, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); + assert_eq!(U256([1, 0, 0, ::std::u64::MAX]), result); + + let (result, _) = U256([0, 0, 0, ::std::u64::MAX]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert_eq!(U256([0, 0, 0, 0]), result); + + let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert_eq!(U256([0, 0, 0, ::std::u64::MAX]), result); + + let (result, _) = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]) + .overflowing_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert_eq!(U256([1, 0, 0, 0]), result); + } + + #[test] + fn u256_multi_muls() { + let (result, _) = U256([0, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, 0])); + assert_eq!(U256([0, 0, 0, 0]), result); + + let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([1, 0, 0, 0])); + assert_eq!(U256([1, 0, 0, 0]), result); + + let (result, _) = U256([5, 0, 0, 0]).overflowing_mul(U256([5, 0, 0, 0])); + assert_eq!(U256([25, 0, 0, 0]), result); + + let (result, _) = U256([0, 5, 0, 0]).overflowing_mul(U256([0, 5, 0, 0])); + assert_eq!(U256([0, 0, 25, 0]), result); + + let (result, _) = U256([0, 0, 0, 1]).overflowing_mul(U256([1, 0, 0, 0])); + assert_eq!(U256([0, 0, 0, 1]), result); + + let (result, _) = U256([0, 0, 0, 5]).overflowing_mul(U256([2, 0, 0, 0])); + assert_eq!(U256([0, 0, 0, 10]), result); + + let (result, _) = U256([0, 0, 1, 0]).overflowing_mul(U256([0, 5, 0, 0])); + assert_eq!(U256([0, 0, 0, 5]), result); + + let (result, _) = U256([0, 0, 8, 0]).overflowing_mul(U256([0, 0, 7, 0])); + assert_eq!(U256([0, 0, 0, 0]), result); + + let (result, _) = U256([2, 0, 0, 0]).overflowing_mul(U256([0, 5, 0, 0])); + assert_eq!(U256([0, 10, 0, 0]), result); + + let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert_eq!(U256([0, 0, 0, ::std::u64::MAX]), result); + } + + #[test] + fn u256_multi_muls_overflow() { + let (_, overflow) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, 0])); + assert!(!overflow); + + let (_, overflow) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert!(!overflow); + + let (_, overflow) = U256([0, 1, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert!(overflow); + + let (_, overflow) = U256([0, 1, 0, 0]).overflowing_mul(U256([0, 1, 0, 0])); + assert!(!overflow); + + let (_, overflow) = U256([0, 1, 0, ::std::u64::MAX]).overflowing_mul(U256([0, 1, 0, ::std::u64::MAX])); + assert!(overflow); + + let (_, overflow) = U256([0, ::std::u64::MAX, 0, 0]).overflowing_mul(U256([0, ::std::u64::MAX, 0, 0])); + assert!(!overflow); + + let (_, overflow) = U256([1, 0, 0, 0]).overflowing_mul(U256([10, 0, 0, 0])); + assert!(!overflow); + + let (_, overflow) = U256([2, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX / 2])); + assert!(!overflow); + + let (_, overflow) = U256([0, 0, 8, 0]).overflowing_mul(U256([0, 0, 7, 0])); + assert!(overflow); + } + + + #[test] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] + fn u256_multi_full_mul() { + let result = U256([0, 0, 0, 0]).full_mul(U256([0, 0, 0, 0])); + assert_eq!(U512([0, 0, 0, 0, 0, 0, 0, 0]), result); + + let result = U256([1, 0, 0, 0]).full_mul(U256([1, 0, 0, 0])); + assert_eq!(U512([1, 0, 0, 0, 0, 0, 0, 0]), result); + + let result = U256([5, 0, 0, 0]).full_mul(U256([5, 0, 0, 0])); + assert_eq!(U512([25, 0, 0, 0, 0, 0, 0, 0]), result); + + let result = U256([0, 5, 0, 0]).full_mul(U256([0, 5, 0, 0])); + assert_eq!(U512([0, 0, 25, 0, 0, 0, 0, 0]), result); + + let result = U256([0, 0, 0, 4]).full_mul(U256([4, 0, 0, 0])); + assert_eq!(U512([0, 0, 0, 16, 0, 0, 0, 0]), result); + + let result = U256([0, 0, 0, 5]).full_mul(U256([2, 0, 0, 0])); + assert_eq!(U512([0, 0, 0, 10, 0, 0, 0, 0]), result); + + let result = U256([0, 0, 2, 0]).full_mul(U256([0, 5, 0, 0])); + assert_eq!(U512([0, 0, 0, 10, 0, 0, 0, 0]), result); + + let result = U256([0, 3, 0, 0]).full_mul(U256([0, 0, 3, 0])); + assert_eq!(U512([0, 0, 0, 9, 0, 0, 0, 0]), result); + + let result = U256([0, 0, 8, 0]).full_mul(U256([0, 0, 6, 0])); + assert_eq!(U512([0, 0, 0, 0, 48, 0, 0, 0]), result); + + let result = U256([9, 0, 0, 0]).full_mul(U256([0, 3, 0, 0])); + assert_eq!(U512([0, 27, 0, 0, 0, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, 0, 0, 0]).full_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U512([1, ::std::u64::MAX-1, 0, 0, 0, 0, 0, 0]), result); + + let result = U256([0, ::std::u64::MAX, 0, 0]).full_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U512([0, 1, ::std::u64::MAX-1, 0, 0, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]).full_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, 0, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); + assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); + assert_eq!(U512([1, 0, ::std::u64::MAX-1, ::std::u64::MAX, 0, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, 0, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); + assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]).full_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, 0, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]).full_mul(U256([::std::u64::MAX, 0, 0, 0])); + assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); + assert_eq!(U512([1, 0, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); + assert_eq!(U512([1, 0, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, 0, 0, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0])); + assert_eq!(U512([1, 0, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, 0, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert_eq!(U512([1, 0, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, 0, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); + assert_eq!(U512([1, 0, 0, ::std::u64::MAX-1, ::std::u64::MAX, ::std::u64::MAX, 0, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert_eq!(U512([1, 0, 0, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, ::std::u64::MAX, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0])); + assert_eq!(U512([1, 0, 0, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, ::std::u64::MAX, 0]), result); + + let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX])); + assert_eq!(U512([1, 0, 0, 0, ::std::u64::MAX-1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]), result); + + let result = U256([0, 0, 0, ::std::u64::MAX]).full_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert_eq!(U512([0, 0, 0, 0, 0, 0, 1, ::std::u64::MAX-1]), result); + + let result = U256([1, 0, 0, 0]).full_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert_eq!(U512([0, 0, 0, ::std::u64::MAX, 0, 0, 0, 0]), result); + + let result = U256([1, 2, 3, 4]).full_mul(U256([5, 0, 0, 0])); + assert_eq!(U512([5, 10, 15, 20, 0, 0, 0, 0]), result); + + let result = U256([1, 2, 3, 4]).full_mul(U256([0, 6, 0, 0])); + assert_eq!(U512([0, 6, 12, 18, 24, 0, 0, 0]), result); + + let result = U256([1, 2, 3, 4]).full_mul(U256([0, 0, 7, 0])); + assert_eq!(U512([0, 0, 7, 14, 21, 28, 0, 0]), result); + + let result = U256([1, 2, 3, 4]).full_mul(U256([0, 0, 0, 8])); + assert_eq!(U512([0, 0, 0, 8, 16, 24, 32, 0]), result); + + let result = U256([1, 2, 3, 4]).full_mul(U256([5, 6, 7, 8])); + assert_eq!(U512([5, 16, 34, 60, 61, 52, 32, 0]), result); + } +} + diff --git a/util/build.rs b/util/build.rs new file mode 100644 index 000000000..1ec89f704 --- /dev/null +++ b/util/build.rs @@ -0,0 +1,37 @@ +// 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 vergen; +extern crate rustc_version; + +use vergen::*; +use std::env; +use std::fs::File; +use std::io::Write; +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(); + f.write_all(format!(" + /// Returns compiler version. + pub fn rustc_version() -> &'static str {{ + \"{}\" + }} + ", rustc_version::version()).as_bytes()).unwrap(); +} diff --git a/util/fdlimit/src/raise_fd_limit.rs b/util/fdlimit/src/raise_fd_limit.rs index f57ac2785..92127da35 100644 --- a/util/fdlimit/src/raise_fd_limit.rs +++ b/util/fdlimit/src/raise_fd_limit.rs @@ -57,5 +57,28 @@ pub unsafe fn raise_fd_limit() { } } -#[cfg(not(any(target_os = "macos", target_os = "ios")))] +#[cfg(any(target_os = "linux"))] +#[allow(non_camel_case_types)] +pub unsafe fn raise_fd_limit() { + use libc; + use std::io; + + // Fetch the current resource limits + let mut rlim = libc::rlimit{rlim_cur: 0, rlim_max: 0}; + if libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) != 0 { + let err = io::Error::last_os_error(); + panic!("raise_fd_limit: error calling getrlimit: {}", err); + } + + // Set soft limit to hard imit + rlim.rlim_cur = rlim.rlim_max; + + // Set our newly-increased resource limit + if libc::setrlimit(libc::RLIMIT_NOFILE, &rlim) != 0 { + let err = io::Error::last_os_error(); + panic!("raise_fd_limit: error calling setrlimit: {}", err); + } +} + +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "linux")))] pub unsafe fn raise_fd_limit() {} diff --git a/util/res/geth_keystore/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9 b/util/res/geth_keystore/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9 new file mode 100644 index 000000000..afc376774 --- /dev/null +++ b/util/res/geth_keystore/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9 @@ -0,0 +1,21 @@ +{ + "address": "3f49624084b67849c7b4e805c5988c21a430f9d9", + "Crypto": { + "cipher": "aes-128-ctr", + "ciphertext": "9f27e3dd4fc73e7103ed61e5493662189a3eb52223ae49e3d1deacc04c889eae", + "cipherparams": { + "iv": "457494bf05f2618c397dc74dbb5181c0" + }, + "kdf": "scrypt", + "kdfparams": { + "dklen": 32, + "n": 262144, + "p": 1, + "r": 8, + "salt": "db14edb18c41ee7f5ec4397df89c3a2ae4d0af60884c52bb54ce490574f8df33" + }, + "mac": "572d24532438d31fdf513c744a3ff26c933ffda5744ee42bc71661cbe3f2112e" + }, + "id": "62a0ad73-556d-496a-8e1c-0783d30d3ace", + "version": 3 +} diff --git a/util/res/geth_keystore/UTC--2016-02-20T09-33-03.984382741Z--5ba4dcf897e97c2bdf8315b9ef26c13c085988cf b/util/res/geth_keystore/UTC--2016-02-20T09-33-03.984382741Z--5ba4dcf897e97c2bdf8315b9ef26c13c085988cf new file mode 100644 index 000000000..b14922037 --- /dev/null +++ b/util/res/geth_keystore/UTC--2016-02-20T09-33-03.984382741Z--5ba4dcf897e97c2bdf8315b9ef26c13c085988cf @@ -0,0 +1,21 @@ +{ + "address": "5ba4dcf897e97c2bdf8315b9ef26c13c085988cf", + "Crypto": { + "cipher": "aes-128-ctr", + "ciphertext": "d4a08ec930163778273920f6ad1d49b71836337be6fd9863993ac700a612fddd", + "cipherparams": { + "iv": "89ce5ec129fc27cd5bcbeb8c92bdad50" + }, + "kdf": "scrypt", + "kdfparams": { + "dklen": 32, + "n": 262144, + "p": 1, + "r": 8, + "salt": "612ab108dc37e69ee8af37a7b24bf7f2234086d7bbf945bacdeccce331f7f84a" + }, + "mac": "4152caa7444e06784223d735cea80cd2690b4c587ad8db3d5529442227b25695" + }, + "id": "35086353-fb12-4029-b56b-033cd61ce35b", + "version": 3 +} diff --git a/util/src/bytes.rs b/util/src/bytes.rs index 5ad2660e8..0683ea4df 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -141,7 +141,7 @@ impl<'a> Deref for BytesRef<'a> { fn deref(&self) -> &[u8] { match *self { BytesRef::Flexible(ref bytes) => bytes, - BytesRef::Fixed(ref bytes) => bytes + BytesRef::Fixed(ref bytes) => bytes, } } } @@ -150,7 +150,7 @@ impl <'a> DerefMut for BytesRef<'a> { fn deref_mut(&mut self) -> &mut [u8] { match *self { BytesRef::Flexible(ref mut bytes) => bytes, - BytesRef::Fixed(ref mut bytes) => bytes + BytesRef::Fixed(ref mut bytes) => bytes, } } } @@ -170,34 +170,14 @@ pub trait BytesConvertable { fn to_bytes(&self) -> Bytes { self.as_slice().to_vec() } } -impl<'a> BytesConvertable for &'a [u8] { - fn bytes(&self) -> &[u8] { self } -} - -impl BytesConvertable for Vec { - fn bytes(&self) -> &[u8] { self } -} - -macro_rules! impl_bytes_convertable_for_array { - ($zero: expr) => (); - ($len: expr, $($idx: expr),*) => { - impl BytesConvertable for [u8; $len] { - fn bytes(&self) -> &[u8] { self } - } - impl_bytes_convertable_for_array! { $($idx),* } - } -} - -// -1 at the end is not expanded -impl_bytes_convertable_for_array! { - 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, - 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1 +impl BytesConvertable for T where T: AsRef<[u8]> { + fn bytes(&self) -> &[u8] { self.as_ref() } } #[test] fn bytes_convertable() { assert_eq!(vec![0x12u8, 0x34].bytes(), &[0x12u8, 0x34]); - assert_eq!([0u8; 0].bytes(), &[]); + assert!([0u8; 0].as_slice().is_empty()); } /// Simple trait to allow for raw population of a Sized object from a byte slice. @@ -252,6 +232,49 @@ impl Populatable for [T] where T: Sized { } } +#[derive(Debug)] +/// Bytes array deserialization error +pub enum FromBytesError { + /// Not enough bytes for the requested type + NotLongEnough, + /// Too many bytes for the requested type + TooLong, +} + +/// Value that can be serialized from bytes array +pub trait FromRawBytes : Sized { + /// function that will instantiate and initialize object from slice + fn from_bytes(d: &[u8]) -> Result; +} + +impl FromRawBytes for T where T: Sized + FixedHash { + fn from_bytes(bytes: &[u8]) -> Result { + use std::mem; + use std::cmp::Ordering; + match bytes.len().cmp(&mem::size_of::()) { + Ordering::Less => return Err(FromBytesError::NotLongEnough), + Ordering::Greater => return Err(FromBytesError::TooLong), + Ordering::Equal => () + }; + + let mut res: Self = unsafe { mem::uninitialized() }; + res.copy_raw(bytes); + Ok(res) + } +} + +impl FromRawBytes for String { + fn from_bytes(bytes: &[u8]) -> Result { + Ok(::std::str::from_utf8(bytes).unwrap().to_owned()) + } +} + +impl FromRawBytes for Vec { + fn from_bytes(bytes: &[u8]) -> Result, FromBytesError> { + Ok(bytes.clone().to_vec()) + } +} + #[test] fn fax_raw() { let mut x = [255u8; 4]; diff --git a/util/src/chainfilter.rs b/util/src/chainfilter.rs deleted file mode 100644 index 20462c698..000000000 --- a/util/src/chainfilter.rs +++ /dev/null @@ -1,469 +0,0 @@ -// 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 . - -//! Multilevel blockchain bloom filter. -//! -//! ``` -//! extern crate ethcore_util as util; -//! use std::str::FromStr; -//! use util::chainfilter::*; -//! use util::sha3::*; -//! use util::hash::*; -//! -//! fn main() { -//! let (index_size, bloom_levels) = (16, 3); -//! let mut cache = MemoryCache::new(); -//! -//! let address = Address::from_str("ef2d6d194084c2de36e0dabfce45d046b37d1106").unwrap(); -//! -//! // borrow cache for reading inside the scope -//! let modified_blooms = { -//! let filter = ChainFilter::new(&cache, index_size, bloom_levels); -//! let block_number = 39; -//! let mut bloom = H2048::new(); -//! bloom.shift_bloomed(&address.sha3()); -//! filter.add_bloom(&bloom, block_number) -//! }; -//! -//! // number of updated blooms is equal number of levels -//! assert_eq!(modified_blooms.len(), bloom_levels as usize); -//! -//! // lets inserts modified blooms into the cache -//! cache.insert_blooms(modified_blooms); -//! -//! // borrow cache for another reading operations -//! { -//! let filter = ChainFilter::new(&cache, index_size, bloom_levels); -//! let blocks = filter.blocks_with_address(&address, 10, 40); -//! assert_eq!(blocks.len(), 1); -//! assert_eq!(blocks[0], 39); -//! } -//! } -//! ``` -//! -use std::collections::{HashMap}; -use hash::*; -use sha3::*; - -/// Represents bloom index in cache -/// -/// On cache level 0, every block bloom is represented by different index. -/// On higher cache levels, multiple block blooms are represented by one -/// index. Their `BloomIndex` can be created from block number and given level. -#[derive(Eq, PartialEq, Hash, Clone, Debug)] -pub struct BloomIndex { - /// Bloom level - pub level: u8, - /// Filter Index - pub index: usize, -} - -impl BloomIndex { - /// Default constructor for `BloomIndex` - pub fn new(level: u8, index: usize) -> BloomIndex { - BloomIndex { - level: level, - index: index, - } - } -} - -/// Types implementing this trait should provide read access for bloom filters database. -pub trait FilterDataSource { - /// returns reference to log at given position if it exists - fn bloom_at_index(&self, index: &BloomIndex) -> Option<&H2048>; -} - -/// In memory cache for blooms. -/// -/// Stores all blooms in HashMap, which indexes them by `BloomIndex`. -pub struct MemoryCache { - blooms: HashMap, -} - -impl MemoryCache { - /// Default constructor for MemoryCache - pub fn new() -> MemoryCache { - MemoryCache { blooms: HashMap::new() } - } - - /// inserts all blooms into cache - /// - /// if bloom at given index already exists, overwrites it - pub fn insert_blooms(&mut self, blooms: HashMap) { - self.blooms.extend(blooms); - } -} - -impl FilterDataSource for MemoryCache { - fn bloom_at_index(&self, index: &BloomIndex) -> Option<&H2048> { - self.blooms.get(index) - } -} - -/// Should be used for search operations on blockchain. -pub struct ChainFilter<'a, D> - where D: FilterDataSource + 'a -{ - data_source: &'a D, - index_size: usize, - level_sizes: Vec, -} - -impl<'a, D> ChainFilter<'a, D> where D: FilterDataSource -{ - /// Creates new filter instance. - /// - /// Borrows `FilterDataSource` for reading. - pub fn new(data_source: &'a D, index_size: usize, levels: u8) -> Self { - if levels == 0 { - panic!("ChainFilter requires at least 1 level"); - } - - let mut filter = ChainFilter { - data_source: data_source, - index_size: index_size, - // 0 level has always a size of 1 - level_sizes: vec![1] - }; - - // cache level sizes, so we do not have to calculate them all the time - // eg. if levels == 3, index_size = 16 - // level_sizes = [1, 16, 256] - let additional: Vec = (1..).into_iter() - .scan(1, |acc, _| { - *acc = *acc * index_size; - Some(*acc) - }) - .take(levels as usize - 1) - .collect(); - filter.level_sizes.extend(additional); - - filter - } - - /// unsafely get level size - fn level_size(&self, level: u8) -> usize { - self.level_sizes[level as usize] - } - - /// converts block number and level to `BloomIndex` - fn bloom_index(&self, block_number: usize, level: u8) -> BloomIndex { - BloomIndex { - level: level, - index: block_number / self.level_size(level), - } - } - - /// return bloom which are dependencies for given index - /// - /// bloom indexes are ordered from lowest to highest - fn lower_level_bloom_indexes(&self, index: &BloomIndex) -> Vec { - // this is the lowest level - if index.level == 0 { - return vec![]; - } - - let new_level = index.level - 1; - let offset = self.index_size * index.index; - - (0..self.index_size).map(|i| BloomIndex::new(new_level, offset + i)).collect() - } - - /// return number of levels - fn levels(&self) -> u8 { - self.level_sizes.len() as u8 - } - - /// returns max filter level - fn max_level(&self) -> u8 { - self.level_sizes.len() as u8 - 1 - } - - /// internal function which does bloom search recursively - fn blocks(&self, bloom: &H2048, from_block: usize, to_block: usize, level: u8, offset: usize) -> Option> { - let index = self.bloom_index(offset, level); - - match self.data_source.bloom_at_index(&index) { - None => return None, - Some(level_bloom) => match level { - // if we are on the lowest level - // take the value, exclude to_block - 0 if offset < to_block => return Some(vec![offset]), - // return None if it is is equal to to_block - 0 => return None, - // return None if current level doesnt contain given bloom - _ if !level_bloom.contains(bloom) => return None, - // continue processing && go down - _ => () - } - }; - - let level_size = self.level_size(level - 1); - let from_index = self.bloom_index(from_block, level - 1); - let to_index = self.bloom_index(to_block, level - 1); - let res: Vec = self.lower_level_bloom_indexes(&index).into_iter() - // chose only blooms in range - .filter(|li| li.index >= from_index.index && li.index <= to_index.index) - // map them to offsets - .map(|li| li.index * level_size) - // get all blocks that may contain our bloom - .map(|off| self.blocks(bloom, from_block, to_block, level - 1, off)) - // filter existing ones - .filter_map(|x| x) - // flatten nested structures - .flat_map(|v| v) - .collect(); - Some(res) - } - - /// Adds new bloom to all filter levels - pub fn add_bloom(&self, bloom: &H2048, block_number: usize) -> HashMap { - let mut result: HashMap = HashMap::new(); - - for level in 0..self.levels() { - let bloom_index = self.bloom_index(block_number, level); - let new_bloom = match self.data_source.bloom_at_index(&bloom_index) { - Some(old_bloom) => old_bloom | bloom, - None => bloom.clone(), - }; - - result.insert(bloom_index, new_bloom); - } - - result - } - - /// Adds new blooms starting from block number. - pub fn add_blooms(&self, blooms: &[H2048], block_number: usize) -> HashMap { - let mut result: HashMap = HashMap::new(); - - for level in 0..self.levels() { - for i in 0..blooms.len() { - let bloom_index = self.bloom_index(block_number + i, level); - let is_new_bloom = match result.get_mut(&bloom_index) { - - // it was already modified - Some(to_shift) => { - *to_shift = &blooms[i] | to_shift; - false - } - None => true, - }; - - // it hasn't been modified yet - if is_new_bloom { - let new_bloom = match self.data_source.bloom_at_index(&bloom_index) { - Some(old_bloom) => old_bloom | &blooms[i], - None => blooms[i].clone(), - }; - result.insert(bloom_index, new_bloom); - } - } - } - - result - } - - /// Resets bloom at level 0 and forces rebuild on higher levels. - pub fn reset_bloom(&self, bloom: &H2048, block_number: usize) -> HashMap { - let mut result: HashMap = HashMap::new(); - - let mut reset_index = self.bloom_index(block_number, 0); - result.insert(reset_index.clone(), bloom.clone()); - - for level in 1..self.levels() { - let index = self.bloom_index(block_number, level); - // get all bloom indexes that were used to construct this bloom - let lower_indexes = self.lower_level_bloom_indexes(&index); - let new_bloom = lower_indexes.into_iter() - // skip reseted one - .filter(|li| li != &reset_index) - // get blooms for these indexes - .map(|li| self.data_source.bloom_at_index(&li)) - // filter existing ones - .filter_map(|b| b) - // BitOr all of them - .fold(H2048::new(), |acc, bloom| &acc | bloom); - - reset_index = index.clone(); - result.insert(index, &new_bloom | bloom); - } - - result - } - - /// Sets lowest level bloom to 0 and forces rebuild on higher levels. - pub fn clear_bloom(&self, block_number: usize) -> HashMap { - self.reset_bloom(&H2048::new(), block_number) - } - - /// Returns numbers of blocks that may contain Address. - pub fn blocks_with_address(&self, address: &Address, from_block: usize, to_block: usize) -> Vec { - let mut bloom = H2048::new(); - bloom.shift_bloomed(&address.sha3()); - self.blocks_with_bloom(&bloom, from_block, to_block) - } - - /// Returns numbers of blocks that may contain Topic. - pub fn blocks_with_topic(&self, topic: &H256, from_block: usize, to_block: usize) -> Vec { - let mut bloom = H2048::new(); - bloom.shift_bloomed(&topic.sha3()); - self.blocks_with_bloom(&bloom, from_block, to_block) - } - - /// Returns numbers of blocks that may log bloom. - pub fn blocks_with_bloom(&self, bloom: &H2048, from_block: usize, to_block: usize) -> Vec { - let mut result = vec![]; - // lets start from highest level - let max_level = self.max_level(); - let level_size = self.level_size(max_level); - let from_index = self.bloom_index(from_block, max_level); - let to_index = self.bloom_index(to_block, max_level); - - for index in from_index.index..to_index.index + 1 { - // offset will be used to calculate where we are right now - let offset = level_size * index; - - // go doooown! - if let Some(blocks) = self.blocks(bloom, from_block, to_block, max_level, offset) { - result.extend(blocks); - } - } - - result - } -} - -#[cfg(test)] -mod tests { - use hash::*; - use chainfilter::*; - use sha3::*; - use std::str::FromStr; - - #[test] - fn test_level_size() { - let cache = MemoryCache::new(); - let filter = ChainFilter::new(&cache, 16, 3); - assert_eq!(filter.level_size(0), 1); - assert_eq!(filter.level_size(1), 16); - assert_eq!(filter.level_size(2), 256); - } - - #[test] - fn test_bloom_index() { - let cache = MemoryCache::new(); - let filter = ChainFilter::new(&cache, 16, 3); - - let bi0 = filter.bloom_index(0, 0); - assert_eq!(bi0.level, 0); - assert_eq!(bi0.index, 0); - - let bi1 = filter.bloom_index(1, 0); - assert_eq!(bi1.level, 0); - assert_eq!(bi1.index, 1); - - let bi2 = filter.bloom_index(2, 0); - assert_eq!(bi2.level, 0); - assert_eq!(bi2.index, 2); - - let bi3 = filter.bloom_index(3, 1); - assert_eq!(bi3.level, 1); - assert_eq!(bi3.index, 0); - - let bi4 = filter.bloom_index(15, 1); - assert_eq!(bi4.level, 1); - assert_eq!(bi4.index, 0); - - let bi5 = filter.bloom_index(16, 1); - assert_eq!(bi5.level, 1); - assert_eq!(bi5.index, 1); - - let bi6 = filter.bloom_index(255, 2); - assert_eq!(bi6.level, 2); - assert_eq!(bi6.index, 0); - - let bi7 = filter.bloom_index(256, 2); - assert_eq!(bi7.level, 2); - assert_eq!(bi7.index, 1); - } - - #[test] - fn test_lower_level_bloom_indexes() { - let cache = MemoryCache::new(); - let filter = ChainFilter::new(&cache, 16, 3); - - let bi = filter.bloom_index(256, 2); - assert_eq!(bi.level, 2); - assert_eq!(bi.index, 1); - - let mut ebis = vec![]; - for i in 16..32 { - ebis.push(BloomIndex::new(1, i)); - } - - let bis = filter.lower_level_bloom_indexes(&bi); - assert_eq!(ebis, bis); - } - - #[test] - fn test_topic_basic_search() { - let index_size = 16; - let bloom_levels = 3; - - let mut cache = MemoryCache::new(); - let topic = H256::from_str("8d936b1bd3fc635710969ccfba471fb17d598d9d1971b538dd712e1e4b4f4dba").unwrap(); - - let modified_blooms = { - let filter = ChainFilter::new(&cache, index_size, bloom_levels); - let block_number = 23; - let mut bloom = H2048::new(); - bloom.shift_bloomed(&topic.sha3()); - filter.add_bloom(&bloom, block_number) - }; - - // number of modified blooms should always be equal number of levels - assert_eq!(modified_blooms.len(), bloom_levels as usize); - cache.insert_blooms(modified_blooms); - - { - let filter = ChainFilter::new(&cache, index_size, bloom_levels); - let blocks = filter.blocks_with_topic(&topic, 0, 100); - assert_eq!(blocks.len(), 1); - assert_eq!(blocks[0], 23); - } - - { - let filter = ChainFilter::new(&cache, index_size, bloom_levels); - let blocks = filter.blocks_with_topic(&topic, 0, 23); - assert_eq!(blocks.len(), 0); - } - - { - let filter = ChainFilter::new(&cache, index_size, bloom_levels); - let blocks = filter.blocks_with_topic(&topic, 23, 24); - assert_eq!(blocks.len(), 1); - assert_eq!(blocks[0], 23); - } - - { - let filter = ChainFilter::new(&cache, index_size, bloom_levels); - let blocks = filter.blocks_with_topic(&topic, 24, 100); - assert_eq!(blocks.len(), 0); - } - } -} diff --git a/util/src/common.rs b/util/src/common.rs index 0816b72e4..b2a06c4b9 100644 --- a/util/src/common.rs +++ b/util/src/common.rs @@ -19,10 +19,9 @@ pub use standard::*; pub use from_json::*; pub use error::*; -pub use hash::*; -pub use uint::*; pub use bytes::*; pub use vector::*; +pub use numbers::*; pub use sha3::*; #[macro_export] diff --git a/util/src/crypto.rs b/util/src/crypto.rs index 792a63ddd..e9b3116fd 100644 --- a/util/src/crypto.rs +++ b/util/src/crypto.rs @@ -16,11 +16,11 @@ //! Ethcore crypto. -use hash::*; +use numbers::*; use bytes::*; -use uint::*; use secp256k1::{key, Secp256k1}; use rand::os::OsRng; +use sha3::Hashable; /// Secret key for secp256k1 EC operations. 256 bit generic "hash" data. pub type Secret = H256; @@ -136,23 +136,29 @@ impl KeyPair { public: p, }) } + /// Returns public key pub fn public(&self) -> &Public { &self.public } + /// Returns private key pub fn secret(&self) -> &Secret { &self.secret } + /// Returns address. + pub fn address(&self) -> Address { + Address::from(self.public.sha3()) + } + /// Sign a message with our secret key. pub fn sign(&self, message: &H256) -> Result { ec::sign(&self.secret, message) } } /// EC functions pub mod ec { - use hash::*; - use uint::*; + use numbers::*; use standard::*; use crypto::*; use crypto::{self}; @@ -254,7 +260,7 @@ pub mod ecies { use crypto::*; /// Encrypt a message with a public key - pub fn encrypt(public: &Public, plain: &[u8]) -> Result { + pub fn encrypt(public: &Public, shared_mac: &[u8], plain: &[u8]) -> Result { use ::rcrypto::digest::Digest; use ::rcrypto::sha2::Sha256; use ::rcrypto::hmac::Hmac; @@ -284,13 +290,14 @@ pub mod ecies { let cipher_iv = &msgd[64..(64 + 16 + plain.len())]; hmac.input(cipher_iv); } + hmac.input(shared_mac); hmac.raw_result(&mut msgd[(64 + 16 + plain.len())..]); } Ok(msg) } /// Decrypt a message with a secret key - pub fn decrypt(secret: &Secret, encrypted: &[u8]) -> Result { + pub fn decrypt(secret: &Secret, shared_mac: &[u8], encrypted: &[u8]) -> Result { use ::rcrypto::digest::Digest; use ::rcrypto::sha2::Sha256; use ::rcrypto::hmac::Hmac; @@ -322,6 +329,7 @@ pub mod ecies { // Verify tag let mut hmac = Hmac::new(Sha256::new(), &mkey); hmac.input(cipher_with_iv); + hmac.input(shared_mac); let mut mac = H256::new(); hmac.raw_result(&mut mac); if &mac[..] != msg_mac { @@ -405,4 +413,20 @@ mod tests { let pair = KeyPair::from_secret(h256_from_hex("6f7b0d801bc7b5ce7bbd930b84fd0369b3eb25d09be58d64ba811091046f3aa2")).unwrap(); assert_eq!(pair.public().hex(), "101b3ef5a4ea7a1c7928e24c4c75fd053c235d7b80c22ae5c03d145d0ac7396e2a4ffff9adee3133a7b05044a5cee08115fd65145e5165d646bde371010d803c"); } + + #[test] + fn ecies_shared() { + let kp = KeyPair::create().unwrap(); + let message = b"So many books, so little time"; + + let shared = b"shared"; + let wrong_shared = b"incorrect"; + let encrypted = ecies::encrypt(kp.public(), shared, message).unwrap(); + assert!(encrypted[..] != message[..]); + assert_eq!(encrypted[0], 0x04); + + assert!(ecies::decrypt(kp.secret(), wrong_shared, &encrypted).is_err()); + let decrypted = ecies::decrypt(kp.secret(), shared, &encrypted).unwrap(); + assert_eq!(decrypted[..message.len()], message[..]); + } } diff --git a/util/src/error.rs b/util/src/error.rs index 68aa3e648..409cc0e5d 100644 --- a/util/src/error.rs +++ b/util/src/error.rs @@ -21,12 +21,13 @@ use network::NetworkError; use rlp::DecoderError; use io; use std::fmt; +use hash::H256; #[derive(Debug)] /// Error in database subsystem. pub enum BaseDataError { /// An entry was removed more times than inserted. - NegativelyReferencedHash, + NegativelyReferencedHash(H256), } #[derive(Debug)] diff --git a/util/src/from_json.rs b/util/src/from_json.rs index 7d977afc9..a598ed961 100644 --- a/util/src/from_json.rs +++ b/util/src/from_json.rs @@ -17,6 +17,7 @@ //! Coversion from json. use standard::*; +use bigint::uint::*; #[macro_export] macro_rules! xjson { @@ -30,3 +31,20 @@ pub trait FromJson { /// Convert a JSON value to an instance of this type. fn from_json(json: &Json) -> Self; } + +impl FromJson for U256 { + fn from_json(json: &Json) -> Self { + match *json { + Json::String(ref s) => { + if s.len() >= 2 && &s[0..2] == "0x" { + FromStr::from_str(&s[2..]).unwrap_or_else(|_| Default::default()) + } else { + Uint::from_dec_str(s).unwrap_or_else(|_| Default::default()) + } + }, + Json::U64(u) => From::from(u), + Json::I64(i) => From::from(i as u64), + _ => Uint::zero(), + } + } +} diff --git a/util/src/hash.rs b/util/src/hash.rs index 2e6c565b4..b7fddbe8b 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -23,7 +23,7 @@ use rand::Rng; use rand::os::OsRng; use bytes::{BytesConvertable,Populatable}; use from_json::*; -use uint::{Uint, U256}; +use bigint::uint::{Uint, U256}; use rustc_serialize::hex::ToHex; use serde; @@ -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 { @@ -77,12 +78,6 @@ macro_rules! impl_hash { /// Unformatted binary data of fixed length. pub struct $from (pub [u8; $size]); - impl BytesConvertable for $from { - fn bytes(&self) -> &[u8] { - &self.0 - } - } - impl Deref for $from { type Target = [u8]; @@ -92,6 +87,13 @@ macro_rules! impl_hash { } } + impl AsRef<[u8]> for $from { + #[inline] + fn as_ref(&self) -> &[u8] { + &self.0 + } + } + impl DerefMut for $from { #[inline] fn deref_mut(&mut self) -> &mut [u8] { @@ -234,11 +236,11 @@ macro_rules! impl_hash { } impl serde::Serialize for $from { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: serde::Serializer { let mut hex = "0x".to_owned(); hex.push_str(self.to_hex().as_ref()); - serializer.visit_str(hex.as_ref()) + serializer.serialize_str(hex.as_ref()) } } @@ -249,14 +251,14 @@ macro_rules! impl_hash { impl serde::de::Visitor for HashVisitor { type Value = $from; - + fn visit_str(&mut self, value: &str) -> Result where E: serde::Error { // 0x + len if value.len() != 2 + $size * 2 { - return Err(serde::Error::syntax("Invalid length.")); + return Err(serde::Error::custom("Invalid length.")); } - value[2..].from_hex().map(|ref v| $from::from_slice(v)).map_err(|_| serde::Error::syntax("Invalid valid hex.")) + value[2..].from_hex().map(|ref v| $from::from_slice(v)).map_err(|_| serde::Error::custom("Invalid hex value.")) } fn visit_string(&mut self, value: String) -> Result where E: serde::Error { @@ -264,7 +266,7 @@ macro_rules! impl_hash { } } - deserializer.visit(HashVisitor) + deserializer.deserialize(HashVisitor) } } @@ -303,6 +305,8 @@ macro_rules! impl_hash { } } + impl Copy for $from {} + #[cfg_attr(feature="dev", allow(expl_impl_clone_on_copy))] impl Clone for $from { fn clone(&self) -> $from { unsafe { @@ -413,15 +417,6 @@ macro_rules! impl_hash { } } - /// Moving BitOrAssign - impl<'a> BitOrAssign<&'a $from> for $from { - fn bitor_assign(&mut self, rhs: &'a Self) { - for i in 0..$size { - self.0[i] = self.0[i] | rhs.0[i]; - } - } - } - /// BitAnd on references impl <'a> BitAnd for &'a $from { type Output = $from; @@ -603,7 +598,7 @@ pub fn h256_from_hex(s: &str) -> H256 { /// Convert `n` to an `H256`, setting the rightmost 8 bytes. pub fn h256_from_u64(n: u64) -> H256 { - use uint::U256; + use bigint::uint::U256; H256::from(&U256::from(n)) } @@ -639,11 +634,11 @@ pub static ZERO_H256: H256 = H256([0x00; 32]); #[cfg(test)] mod tests { use hash::*; - use uint::*; + use bigint::uint::*; use std::str::FromStr; #[test] - #[allow(eq_op)] + #[cfg_attr(feature="dev", allow(eq_op))] fn hash() { let h = H64([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]); assert_eq!(H64::from_str("0123456789abcdef").unwrap(), h); @@ -727,4 +722,3 @@ mod tests { assert_eq!(r, u); } } - diff --git a/util/src/hashdb.rs b/util/src/hashdb.rs index 4d8cbaba1..e622c4b99 100644 --- a/util/src/hashdb.rs +++ b/util/src/hashdb.rs @@ -20,7 +20,7 @@ use bytes::*; use std::collections::HashMap; /// Trait modelling datastore keyed by a 32-byte Keccak hash. -pub trait HashDB { +pub trait HashDB : AsHashDB { /// Get the keys in the database together with number of underlying references. fn keys(&self) -> HashMap; @@ -111,3 +111,16 @@ pub trait HashDB { /// ``` fn remove(&mut self, key: &H256) { self.kill(key) } } + +/// Upcast trait. +pub trait AsHashDB { + /// Perform upcast to HashDB for anything that derives from HashDB. + fn as_hashdb(&self) -> &HashDB; + /// Perform mutable upcast to HashDB for anything that derives from HashDB. + fn as_hashdb_mut(&mut self) -> &mut HashDB; +} + +impl AsHashDB for T { + fn as_hashdb(&self) -> &HashDB { self } + fn as_hashdb_mut(&mut self) -> &mut HashDB { self } +} diff --git a/util/src/heapsizeof.rs b/util/src/heapsizeof.rs index d7c8124cd..feb679a0b 100644 --- a/util/src/heapsizeof.rs +++ b/util/src/heapsizeof.rs @@ -16,8 +16,7 @@ //! Calculates heapsize of util types. -use uint::*; use hash::*; known_heap_size!(0, H32, H64, H128, Address, H256, H264, H512, H520, H1024, H2048); -known_heap_size!(0, U128, U256); + diff --git a/util/src/io/service.rs b/util/src/io/service.rs index c5f4a6072..8a34ee80a 100644 --- a/util/src/io/service.rs +++ b/util/src/io/service.rs @@ -153,7 +153,7 @@ struct UserTimer { pub struct IoManager where Message: Send + Sync { timers: Arc>>, handlers: Vec>>, - _workers: Vec, + workers: Vec, worker_channel: chase_lev::Worker>, work_ready: Arc, } @@ -180,7 +180,7 @@ impl IoManager where Message: Send + Sync + Clone + 'static { timers: Arc::new(RwLock::new(HashMap::new())), handlers: Vec::new(), worker_channel: worker, - _workers: workers, + workers: workers, work_ready: work_ready, }; try!(event_loop.run(&mut io)); @@ -230,7 +230,10 @@ impl Handler for IoManager where Message: Send + Clone + Sync fn notify(&mut self, event_loop: &mut EventLoop, msg: Self::Message) { match msg { - IoMessage::Shutdown => event_loop.shutdown(), + IoMessage::Shutdown => { + self.workers.clear(); + event_loop.shutdown(); + }, IoMessage::AddHandler { handler } => { let handler_id = { self.handlers.push(handler.clone()); @@ -256,6 +259,11 @@ impl Handler for IoManager where Message: Send + Clone + Sync IoMessage::DeregisterStream { handler_id, token } => { let handler = self.handlers.get(handler_id).expect("Unknown handler id").clone(); handler.deregister_stream(token, event_loop); + // unregister a timer associated with the token (if any) + let timer_id = token + handler_id * TOKENS_PER_HANDLER; + if let Some(timer) = self.timers.write().unwrap().remove(&timer_id) { + event_loop.clear_timeout(timer.timeout); + } }, IoMessage::UpdateStreamRegistration { handler_id, token } => { let handler = self.handlers.get(handler_id).expect("Unknown handler id").clone(); diff --git a/util/src/io/worker.rs b/util/src/io/worker.rs index 1ba0318bc..b874ea0a4 100644 --- a/util/src/io/worker.rs +++ b/util/src/io/worker.rs @@ -44,6 +44,7 @@ pub struct Worker { thread: Option>, wait: Arc, deleting: Arc, + wait_mutex: Arc>, } impl Worker { @@ -61,6 +62,7 @@ impl Worker { thread: None, wait: wait.clone(), deleting: deleting.clone(), + wait_mutex: wait_mutex.clone(), }; worker.thread = Some(thread::Builder::new().name(format!("IO Worker #{}", index)).spawn( move || { @@ -77,13 +79,17 @@ impl Worker { wait_mutex: Arc>, deleting: Arc) where Message: Send + Sync + Clone + 'static { - while !deleting.load(AtomicOrdering::Relaxed) { + loop { { let lock = wait_mutex.lock().unwrap(); - let _ = wait.wait(lock).unwrap(); - if deleting.load(AtomicOrdering::Relaxed) { + if deleting.load(AtomicOrdering::Acquire) { return; } + let _ = wait.wait(lock).unwrap(); + } + + if deleting.load(AtomicOrdering::Acquire) { + return; } while let chase_lev::Steal::Data(work) = stealer.steal() { Worker::do_work(work, channel.clone()); @@ -114,7 +120,8 @@ impl Worker { impl Drop for Worker { fn drop(&mut self) { - self.deleting.store(true, AtomicOrdering::Relaxed); + let _ = self.wait_mutex.lock(); + self.deleting.store(true, AtomicOrdering::Release); self.wait.notify_all(); let thread = mem::replace(&mut self.thread, None).unwrap(); thread.join().ok(); diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs deleted file mode 100644 index 7b810639b..000000000 --- a/util/src/journaldb.rs +++ /dev/null @@ -1,457 +0,0 @@ -// 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 . - -//! Disk-backed HashDB implementation. - -use common::*; -use rlp::*; -use hashdb::*; -use memorydb::*; -use rocksdb::{DB, Writable, WriteBatch, IteratorMode}; -#[cfg(test)] -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 -/// 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. -pub struct JournalDB { - overlay: MemoryDB, - backing: Arc, - counters: Arc>>, -} - -impl Clone for JournalDB { - fn clone(&self) -> JournalDB { - JournalDB { - overlay: MemoryDB::new(), - backing: self.backing.clone(), - counters: self.counters.clone(), - } - } -} - -const LATEST_ERA_KEY : [u8; 4] = [ b'l', b'a', b's', b't' ]; -const VERSION_KEY : [u8; 4] = [ b'j', b'v', b'e', b'r' ]; - -const DB_VERSION: u32 = 2; - -impl JournalDB { - /// Create a new instance given a `backing` database. - pub fn new(backing: DB) -> JournalDB { - let db = Arc::new(backing); - JournalDB::new_with_arc(db) - } - - /// Create a new instance given a shared `backing` database. - pub fn new_with_arc(backing: Arc) -> JournalDB { - if backing.iterator(IteratorMode::Start).next().is_some() { - match backing.get(&VERSION_KEY).map(|d| d.map(|v| decode::(&v))) { - Ok(Some(DB_VERSION)) => {}, - v => panic!("Incompatible DB version, expected {}, got {:?}", DB_VERSION, v) - } - } else { - backing.put(&VERSION_KEY, &encode(&DB_VERSION)).expect("Error writing version to database"); - } - let counters = JournalDB::read_counters(&backing); - JournalDB { - overlay: MemoryDB::new(), - backing: backing, - counters: Arc::new(RwLock::new(counters)), - } - } - - /// Create a new instance with an anonymous temporary database. - #[cfg(test)] - pub fn new_temp() -> JournalDB { - let mut dir = env::temp_dir(); - dir.push(H32::random().hex()); - Self::new(DB::open_default(dir.to_str().unwrap()).unwrap()) - } - - /// Check if this database has any commits - pub fn is_empty(&self) -> bool { - self.backing.get(&LATEST_ERA_KEY).expect("Low level database error").is_none() - } - - /// Commit all recent insert operations and historical removals from the old era - /// to the backing database. - pub fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { - // journal format: - // [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] - // [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] - // [era, n] => [ ... ] - - // TODO: store 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, - // we remove all of its removes assuming it is canonical and all - // of its inserts otherwise. - // - // We also keep reference counters for each key inserted in the journal to handle - // the following cases where key K must not be deleted from the DB when processing removals : - // Given H is the journal size in eras, 0 <= C <= H. - // Key K is removed in era A(N) and re-inserted in canonical era B(N + C). - // Key K is removed in era A(N) and re-inserted in non-canonical era B`(N + C). - // Key K is added in non-canonical era A'(N) canonical B(N + C). - // - // The counter is encreased each time a key is inserted in the journal in the commit. The list of insertions - // is saved with the era record. When the era becomes end_era and goes out of journal the counter is decreased - // and the key is safe to delete. - - // record new commit's details. - let batch = WriteBatch::new(); - let mut counters = self.counters.write().unwrap(); - { - let mut index = 0usize; - let mut last; - - while try!(self.backing.get({ - let mut r = RlpStream::new_list(2); - r.append(&now); - r.append(&index); - last = r.drain(); - &last - })).is_some() { - index += 1; - } - - let mut r = RlpStream::new_list(3); - let inserts: Vec = self.overlay.keys().iter().filter(|&(_, &c)| c > 0).map(|(key, _)| key.clone()).collect(); - // Increase counter for each inserted key no matter if the block is canonical or not. - for i in &inserts { - *counters.entry(i.clone()).or_insert(0) += 1; - } - let removes: Vec = self.overlay.keys().iter().filter(|&(_, &c)| c < 0).map(|(key, _)| key.clone()).collect(); - r.append(id); - r.append(&inserts); - r.append(&removes); - try!(batch.put(&last, r.as_raw())); - try!(batch.put(&LATEST_ERA_KEY, &encode(&now))); - } - - // apply old commits' details - if let Some((end_era, canon_id)) = end { - let mut index = 0usize; - let mut last; - let mut to_remove: Vec = Vec::new(); - let mut canon_inserts: Vec = Vec::new(); - while let Some(rlp_data) = try!(self.backing.get({ - let mut r = RlpStream::new_list(2); - r.append(&end_era); - r.append(&index); - last = r.drain(); - &last - })) { - let rlp = Rlp::new(&rlp_data); - let inserts: Vec = rlp.val_at(1); - JournalDB::decrease_counters(&inserts, &mut counters); - // Collect keys to be removed. These are removed keys for canonical block, inserted for non-canonical - if canon_id == rlp.val_at(0) { - to_remove.extend(rlp.at(2).iter().map(|r| r.as_val::())); - canon_inserts = inserts; - } - else { - to_remove.extend(inserts); - } - try!(batch.delete(&last)); - index += 1; - } - - let canon_inserts = canon_inserts.drain(..).collect::>(); - // Purge removed keys if they are not referenced and not re-inserted in the canon commit - let mut deletes = 0; - for h in to_remove.iter().filter(|h| !counters.contains_key(h) && !canon_inserts.contains(h)) { - try!(batch.delete(&h)); - deletes += 1; - } - trace!("JournalDB: delete journal for time #{}.{}, (canon was {}): {} entries", end_era, index, canon_id, deletes); - } - - // Commit overlay insertions - let mut ret = 0u32; - let mut deletes = 0usize; - for i in self.overlay.drain().into_iter() { - let (key, (value, rc)) = i; - if rc > 0 { - assert!(rc == 1); - batch.put(&key.bytes(), &value).expect("Low-level database error. Some issue with your hard disk?"); - ret += 1; - } - if rc < 0 { - assert!(rc == -1); - ret += 1; - deletes += 1; - } - } - - try!(self.backing.write(batch)); - trace!("JournalDB::commit() deleted {} nodes", deletes); - Ok(ret) - } - - - // Decrease counters for given keys. Deletes obsolete counters - fn decrease_counters(keys: &[H256], counters: &mut HashMap) { - for i in keys.iter() { - let delete_counter = { - let cnt = counters.get_mut(i).expect("Missing key counter"); - *cnt -= 1; - *cnt == 0 - }; - if delete_counter { - counters.remove(i); - } - } - } - - fn payload(&self, key: &H256) -> Option { - self.backing.get(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?").map(|v| v.to_vec()) - } - - fn read_counters(db: &DB) -> HashMap { - let mut res = HashMap::new(); - if let Some(val) = db.get(&LATEST_ERA_KEY).expect("Low-level database error.") { - let mut era = decode::(&val); - loop { - let mut index = 0usize; - while let Some(rlp_data) = db.get({ - let mut r = RlpStream::new_list(2); - r.append(&era); - r.append(&index); - &r.drain() - }).expect("Low-level database error.") { - let rlp = Rlp::new(&rlp_data); - let to_add: Vec = rlp.val_at(1); - for h in to_add { - *res.entry(h).or_insert(0) += 1; - } - index += 1; - }; - if index == 0 || era == 0 { - break; - } - era -= 1; - } - } - trace!("Recovered {} counters", res.len()); - res - } -} - -impl HashDB for JournalDB { - fn keys(&self) -> HashMap { - let mut ret: HashMap = HashMap::new(); - for (key, _) in self.backing.iterator(IteratorMode::Start) { - let h = H256::from_slice(key.deref()); - ret.insert(h, 1); - } - - for (key, refs) in self.overlay.keys().into_iter() { - let refs = *ret.get(&key).unwrap_or(&0) + refs; - ret.insert(key, refs); - } - ret - } - - fn lookup(&self, key: &H256) -> Option<&[u8]> { - let k = self.overlay.raw(key); - match k { - Some(&(ref d, rc)) if rc > 0 => Some(d), - _ => { - if let Some(x) = self.payload(key) { - Some(&self.overlay.denote(key, x).0) - } - else { - None - } - } - } - } - - fn exists(&self, key: &H256) -> bool { - self.lookup(key).is_some() - } - - fn insert(&mut self, value: &[u8]) -> H256 { - self.overlay.insert(value) - } - fn emplace(&mut self, key: H256, value: Bytes) { - self.overlay.emplace(key, value); - } - fn kill(&mut self, key: &H256) { - self.overlay.kill(key); - } -} - -#[cfg(test)] -mod tests { - use common::*; - use super::*; - use hashdb::*; - - #[test] - fn long_history() { - // history is 3 - let mut jdb = JournalDB::new_temp(); - let h = jdb.insert(b"foo"); - jdb.commit(0, &b"0".sha3(), None).unwrap(); - assert!(jdb.exists(&h)); - jdb.remove(&h); - jdb.commit(1, &b"1".sha3(), None).unwrap(); - assert!(jdb.exists(&h)); - jdb.commit(2, &b"2".sha3(), None).unwrap(); - assert!(jdb.exists(&h)); - jdb.commit(3, &b"3".sha3(), Some((0, b"0".sha3()))).unwrap(); - assert!(jdb.exists(&h)); - jdb.commit(4, &b"4".sha3(), Some((1, b"1".sha3()))).unwrap(); - assert!(!jdb.exists(&h)); - } - - #[test] - fn complex() { - // history is 1 - let mut jdb = JournalDB::new_temp(); - - let foo = jdb.insert(b"foo"); - let bar = jdb.insert(b"bar"); - jdb.commit(0, &b"0".sha3(), None).unwrap(); - assert!(jdb.exists(&foo)); - assert!(jdb.exists(&bar)); - - jdb.remove(&foo); - jdb.remove(&bar); - let baz = jdb.insert(b"baz"); - jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); - assert!(jdb.exists(&foo)); - assert!(jdb.exists(&bar)); - assert!(jdb.exists(&baz)); - - let foo = jdb.insert(b"foo"); - jdb.remove(&baz); - jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); - assert!(jdb.exists(&foo)); - assert!(!jdb.exists(&bar)); - assert!(jdb.exists(&baz)); - - jdb.remove(&foo); - jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); - assert!(jdb.exists(&foo)); - assert!(!jdb.exists(&bar)); - assert!(!jdb.exists(&baz)); - - jdb.commit(4, &b"4".sha3(), Some((3, b"3".sha3()))).unwrap(); - assert!(!jdb.exists(&foo)); - assert!(!jdb.exists(&bar)); - assert!(!jdb.exists(&baz)); - } - - #[test] - fn fork() { - // history is 1 - let mut jdb = JournalDB::new_temp(); - - let foo = jdb.insert(b"foo"); - let bar = jdb.insert(b"bar"); - jdb.commit(0, &b"0".sha3(), None).unwrap(); - assert!(jdb.exists(&foo)); - assert!(jdb.exists(&bar)); - - jdb.remove(&foo); - let baz = jdb.insert(b"baz"); - jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); - - jdb.remove(&bar); - jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); - - assert!(jdb.exists(&foo)); - assert!(jdb.exists(&bar)); - assert!(jdb.exists(&baz)); - - jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); - assert!(jdb.exists(&foo)); - assert!(!jdb.exists(&baz)); - assert!(!jdb.exists(&bar)); - } - - #[test] - fn overwrite() { - // history is 1 - let mut jdb = JournalDB::new_temp(); - - let foo = jdb.insert(b"foo"); - jdb.commit(0, &b"0".sha3(), None).unwrap(); - assert!(jdb.exists(&foo)); - - jdb.remove(&foo); - jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); - jdb.insert(b"foo"); - assert!(jdb.exists(&foo)); - jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); - assert!(jdb.exists(&foo)); - jdb.commit(3, &b"2".sha3(), Some((0, b"2".sha3()))).unwrap(); - assert!(jdb.exists(&foo)); - } - - #[test] - fn fork_same_key() { - // history is 1 - let mut jdb = JournalDB::new_temp(); - jdb.commit(0, &b"0".sha3(), None).unwrap(); - - let foo = jdb.insert(b"foo"); - jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); - - jdb.insert(b"foo"); - jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); - assert!(jdb.exists(&foo)); - - jdb.commit(2, &b"2a".sha3(), Some((1, b"1a".sha3()))).unwrap(); - assert!(jdb.exists(&foo)); - } - - #[test] - fn reopen() { - use rocksdb::DB; - let mut dir = ::std::env::temp_dir(); - dir.push(H32::random().hex()); - - let foo = { - let mut jdb = JournalDB::new(DB::open_default(dir.to_str().unwrap()).unwrap()); - // history is 1 - let foo = jdb.insert(b"foo"); - jdb.commit(0, &b"0".sha3(), None).unwrap(); - foo - }; - - { - let mut jdb = JournalDB::new(DB::open_default(dir.to_str().unwrap()).unwrap()); - jdb.remove(&foo); - jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); - } - - { - let mut jdb = JournalDB::new(DB::open_default(dir.to_str().unwrap()).unwrap()); - assert!(jdb.exists(&foo)); - jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); - assert!(!jdb.exists(&foo)); - } - } -} diff --git a/util/src/journaldb/archivedb.rs b/util/src/journaldb/archivedb.rs new file mode 100644 index 000000000..76f0ecc50 --- /dev/null +++ b/util/src/journaldb/archivedb.rs @@ -0,0 +1,420 @@ +// 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 . + +//! Disk-backed HashDB implementation. + +use common::*; +use rlp::*; +use hashdb::*; +use memorydb::*; +use super::traits::JournalDB; +use kvdb::{Database, DBTransaction, DatabaseConfig}; +#[cfg(test)] +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 +/// 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. +pub struct ArchiveDB { + overlay: MemoryDB, + backing: Arc, + latest_era: Option, +} + +// all keys must be at least 12 bytes +const LATEST_ERA_KEY : [u8; 12] = [ b'l', b'a', b's', b't', 0, 0, 0, 0, 0, 0, 0, 0 ]; +const VERSION_KEY : [u8; 12] = [ b'j', b'v', b'e', b'r', 0, 0, 0, 0, 0, 0, 0, 0 ]; +const DB_VERSION : u32 = 259; + +impl ArchiveDB { + /// Create a new instance from file + pub fn new(path: &str) -> ArchiveDB { + let opts = DatabaseConfig { + prefix_size: Some(12) //use 12 bytes as prefix, this must match account_db prefix + }; + let backing = Database::open(&opts, path).unwrap_or_else(|e| { + panic!("Error opening state db: {}", e); + }); + if !backing.is_empty() { + match backing.get(&VERSION_KEY).map(|d| d.map(|v| decode::(&v))) { + Ok(Some(DB_VERSION)) => {}, + v => panic!("Incompatible DB version, expected {}, got {:?}", DB_VERSION, v) + } + } else { + backing.put(&VERSION_KEY, &encode(&DB_VERSION)).expect("Error writing version to database"); + } + + let latest_era = backing.get(&LATEST_ERA_KEY).expect("Low-level database error.").map(|val| decode::(&val)); + ArchiveDB { + overlay: MemoryDB::new(), + backing: Arc::new(backing), + latest_era: latest_era, + } + } + + /// Create a new instance with an anonymous temporary database. + #[cfg(test)] + fn new_temp() -> ArchiveDB { + let mut dir = env::temp_dir(); + dir.push(H32::random().hex()); + Self::new(dir.to_str().unwrap()) + } + + fn payload(&self, key: &H256) -> Option { + self.backing.get(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?").map(|v| v.to_vec()) + } +} + +impl HashDB for ArchiveDB { + fn keys(&self) -> HashMap { + let mut ret: HashMap = HashMap::new(); + for (key, _) in self.backing.iter() { + let h = H256::from_slice(key.deref()); + ret.insert(h, 1); + } + + for (key, refs) in self.overlay.keys().into_iter() { + let refs = *ret.get(&key).unwrap_or(&0) + refs; + ret.insert(key, refs); + } + ret + } + + fn lookup(&self, key: &H256) -> Option<&[u8]> { + let k = self.overlay.raw(key); + match k { + Some(&(ref d, rc)) if rc > 0 => Some(d), + _ => { + if let Some(x) = self.payload(key) { + Some(&self.overlay.denote(key, x).0) + } + else { + None + } + } + } + } + + fn exists(&self, key: &H256) -> bool { + self.lookup(key).is_some() + } + + fn insert(&mut self, value: &[u8]) -> H256 { + self.overlay.insert(value) + } + fn emplace(&mut self, key: H256, value: Bytes) { + self.overlay.emplace(key, value); + } + fn kill(&mut self, key: &H256) { + self.overlay.kill(key); + } +} + +impl JournalDB for ArchiveDB { + fn spawn(&self) -> Box { + Box::new(ArchiveDB { + overlay: MemoryDB::new(), + backing: self.backing.clone(), + latest_era: self.latest_era, + }) + } + + fn mem_used(&self) -> usize { + self.overlay.mem_used() + } + + fn is_empty(&self) -> bool { + self.latest_era.is_none() + } + + fn commit(&mut self, now: u64, _: &H256, _: Option<(u64, H256)>) -> Result { + let batch = DBTransaction::new(); + let mut inserts = 0usize; + let mut deletes = 0usize; + for i in self.overlay.drain().into_iter() { + let (key, (value, rc)) = i; + if rc > 0 { + assert!(rc == 1); + batch.put(&key.bytes(), &value).expect("Low-level database error. Some issue with your hard disk?"); + inserts += 1; + } + if rc < 0 { + assert!(rc == -1); + deletes += 1; + } + } + if self.latest_era.map_or(true, |e| now > e) { + try!(batch.put(&LATEST_ERA_KEY, &encode(&now))); + self.latest_era = Some(now); + } + try!(self.backing.write(batch)); + Ok((inserts + deletes) as u32) + } + + fn state(&self, id: &H256) -> Option { + self.backing.get_by_prefix(&id.bytes()[0..12]).and_then(|b| Some(b.to_vec())) + } +} + +#[cfg(test)] +mod tests { + #![cfg_attr(feature="dev", allow(blacklisted_name))] + + use common::*; + use super::*; + use hashdb::*; + use journaldb::traits::JournalDB; + + #[test] + fn insert_same_in_fork() { + // history is 1 + let mut jdb = ArchiveDB::new_temp(); + + let x = jdb.insert(b"X"); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + jdb.commit(2, &b"2".sha3(), None).unwrap(); + jdb.commit(3, &b"1002a".sha3(), Some((1, b"1".sha3()))).unwrap(); + jdb.commit(4, &b"1003a".sha3(), Some((2, b"2".sha3()))).unwrap(); + + jdb.remove(&x); + jdb.commit(3, &b"1002b".sha3(), Some((1, b"1".sha3()))).unwrap(); + let x = jdb.insert(b"X"); + jdb.commit(4, &b"1003b".sha3(), Some((2, b"2".sha3()))).unwrap(); + + jdb.commit(5, &b"1004a".sha3(), Some((3, b"1002a".sha3()))).unwrap(); + jdb.commit(6, &b"1005a".sha3(), Some((4, b"1003a".sha3()))).unwrap(); + + assert!(jdb.exists(&x)); + } + + #[test] + fn long_history() { + // history is 3 + let mut jdb = ArchiveDB::new_temp(); + let h = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.exists(&h)); + jdb.remove(&h); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.exists(&h)); + jdb.commit(2, &b"2".sha3(), None).unwrap(); + assert!(jdb.exists(&h)); + jdb.commit(3, &b"3".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.exists(&h)); + jdb.commit(4, &b"4".sha3(), Some((1, b"1".sha3()))).unwrap(); + } + + #[test] + fn complex() { + // history is 1 + let mut jdb = ArchiveDB::new_temp(); + + let foo = jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + + jdb.remove(&foo); + jdb.remove(&bar); + let baz = jdb.insert(b"baz"); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + assert!(jdb.exists(&baz)); + + let foo = jdb.insert(b"foo"); + jdb.remove(&baz); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&baz)); + + jdb.remove(&foo); + jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + + jdb.commit(4, &b"4".sha3(), Some((3, b"3".sha3()))).unwrap(); + } + + #[test] + fn fork() { + // history is 1 + let mut jdb = ArchiveDB::new_temp(); + + let foo = jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + + jdb.remove(&foo); + let baz = jdb.insert(b"baz"); + jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + + jdb.remove(&bar); + jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + assert!(jdb.exists(&baz)); + + jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + } + + #[test] + fn overwrite() { + // history is 1 + let mut jdb = ArchiveDB::new_temp(); + + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.exists(&foo)); + + jdb.remove(&foo); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + jdb.insert(b"foo"); + assert!(jdb.exists(&foo)); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + jdb.commit(3, &b"2".sha3(), Some((0, b"2".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + } + + #[test] + fn fork_same_key() { + // history is 1 + let mut jdb = ArchiveDB::new_temp(); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + + let foo = jdb.insert(b"foo"); + jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + + jdb.insert(b"foo"); + jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + + jdb.commit(2, &b"2a".sha3(), Some((1, b"1a".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + } + + #[test] + fn reopen() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + let bar = H256::random(); + + let foo = { + let mut jdb = ArchiveDB::new(dir.to_str().unwrap()); + // history is 1 + let foo = jdb.insert(b"foo"); + jdb.emplace(bar.clone(), b"bar".to_vec()); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + foo + }; + + { + let mut jdb = ArchiveDB::new(dir.to_str().unwrap()); + jdb.remove(&foo); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + } + + { + let mut jdb = ArchiveDB::new(dir.to_str().unwrap()); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + } + } + + #[test] + fn reopen_remove() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let foo = { + let mut jdb = ArchiveDB::new(dir.to_str().unwrap()); + // history is 1 + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + + // foo is ancient history. + + jdb.insert(b"foo"); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + foo + }; + + { + let mut jdb = ArchiveDB::new(dir.to_str().unwrap()); + jdb.remove(&foo); + jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + jdb.remove(&foo); + jdb.commit(4, &b"4".sha3(), Some((3, b"3".sha3()))).unwrap(); + jdb.commit(5, &b"5".sha3(), Some((4, b"4".sha3()))).unwrap(); + } + } + + #[test] + fn reopen_fork() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + let (foo, _, _) = { + let mut jdb = ArchiveDB::new(dir.to_str().unwrap()); + // history is 1 + let foo = jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + jdb.remove(&foo); + let baz = jdb.insert(b"baz"); + jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + + jdb.remove(&bar); + jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + (foo, bar, baz) + }; + + { + let mut jdb = ArchiveDB::new(dir.to_str().unwrap()); + jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + } + } + + #[test] + fn returns_state() { + let temp = ::devtools::RandomTempPath::new(); + + let key = { + let mut jdb = ArchiveDB::new(temp.as_str()); + let key = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + key + }; + + { + let jdb = ArchiveDB::new(temp.as_str()); + let state = jdb.state(&key); + assert!(state.is_some()); + } + } +} diff --git a/util/src/journaldb/earlymergedb.rs b/util/src/journaldb/earlymergedb.rs new file mode 100644 index 000000000..15dcacd6a --- /dev/null +++ b/util/src/journaldb/earlymergedb.rs @@ -0,0 +1,1064 @@ +// 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 . + +//! Disk-backed HashDB implementation. + +use common::*; +use rlp::*; +use hashdb::*; +use memorydb::*; +use super::traits::JournalDB; +use kvdb::{Database, DBTransaction, DatabaseConfig}; +#[cfg(test)] +use std::env; + +#[derive(Clone, PartialEq, Eq)] +struct RefInfo { + queue_refs: usize, + in_archive: bool, +} + +impl HeapSizeOf for RefInfo { + fn heap_size_of_children(&self) -> usize { 0 } +} + +impl fmt::Display for RefInfo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}+{}", self.queue_refs, if self.in_archive {1} else {0}) + } +} + +impl fmt::Debug for RefInfo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}+{}", self.queue_refs, if self.in_archive {1} else {0}) + } +} + +#[derive(Clone, PartialEq, Eq)] +enum RemoveFrom { + Queue, + Archive, +} + +/// 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 +/// 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. +pub struct EarlyMergeDB { + overlay: MemoryDB, + backing: Arc, + refs: Option>>>, + latest_era: Option, +} + +// all keys must be at least 12 bytes +const LATEST_ERA_KEY : [u8; 12] = [ b'l', b'a', b's', b't', 0, 0, 0, 0, 0, 0, 0, 0 ]; +const VERSION_KEY : [u8; 12] = [ b'j', b'v', b'e', b'r', 0, 0, 0, 0, 0, 0, 0, 0 ]; +const DB_VERSION : u32 = 3; +const PADDING : [u8; 10] = [ 0u8; 10 ]; + +impl EarlyMergeDB { + /// Create a new instance from file + pub fn new(path: &str) -> EarlyMergeDB { + let opts = DatabaseConfig { + prefix_size: Some(12) //use 12 bytes as prefix, this must match account_db prefix + }; + let backing = Database::open(&opts, path).unwrap_or_else(|e| { + panic!("Error opening state db: {}", e); + }); + if !backing.is_empty() { + match backing.get(&VERSION_KEY).map(|d| d.map(|v| decode::(&v))) { + Ok(Some(DB_VERSION)) => {}, + v => panic!("Incompatible DB version, expected {}, got {:?}", DB_VERSION, v) + } + } else { + backing.put(&VERSION_KEY, &encode(&DB_VERSION)).expect("Error writing version to database"); + } + + let (latest_era, refs) = EarlyMergeDB::read_refs(&backing); + let refs = Some(Arc::new(RwLock::new(refs))); + EarlyMergeDB { + overlay: MemoryDB::new(), + backing: Arc::new(backing), + refs: refs, + latest_era: latest_era, + } + } + + /// Create a new instance with an anonymous temporary database. + #[cfg(test)] + fn new_temp() -> EarlyMergeDB { + let mut dir = env::temp_dir(); + dir.push(H32::random().hex()); + Self::new(dir.to_str().unwrap()) + } + + fn morph_key(key: &H256, index: u8) -> Bytes { + let mut ret = key.bytes().to_owned(); + ret.push(index); + ret + } + + // The next three are valid only as long as there is an insert operation of `key` in the journal. + fn set_already_in(batch: &DBTransaction, key: &H256) { batch.put(&Self::morph_key(key, 0), &[1u8]).expect("Low-level database error. Some issue with your hard disk?"); } + fn reset_already_in(batch: &DBTransaction, key: &H256) { batch.delete(&Self::morph_key(key, 0)).expect("Low-level database error. Some issue with your hard disk?"); } + fn is_already_in(backing: &Database, key: &H256) -> bool { + backing.get(&Self::morph_key(key, 0)).expect("Low-level database error. Some issue with your hard disk?").is_some() + } + + fn insert_keys(inserts: &[(H256, Bytes)], backing: &Database, refs: &mut HashMap, batch: &DBTransaction, trace: bool) { + for &(ref h, ref d) in inserts { + if let Some(c) = refs.get_mut(h) { + // already counting. increment. + c.queue_refs += 1; + if trace { + trace!(target: "jdb.fine", " insert({}): In queue: Incrementing refs to {}", h, c.queue_refs); + } + continue; + } + + // this is the first entry for this node in the journal. + if backing.get(&h.bytes()).expect("Low-level database error. Some issue with your hard disk?").is_some() { + // already in the backing DB. start counting, and remember it was already in. + Self::set_already_in(batch, &h); + refs.insert(h.clone(), RefInfo{queue_refs: 1, in_archive: true}); + if trace { + trace!(target: "jdb.fine", " insert({}): New to queue, in DB: Recording and inserting into queue", h); + } + continue; + } + + // Gets removed when a key leaves the journal, so should never be set when we're placing a new key. + //Self::reset_already_in(&h); + assert!(!Self::is_already_in(backing, &h)); + batch.put(&h.bytes(), d).expect("Low-level database error. Some issue with your hard disk?"); + refs.insert(h.clone(), RefInfo{queue_refs: 1, in_archive: false}); + if trace { + trace!(target: "jdb.fine", " insert({}): New to queue, not in DB: Inserting into queue and DB", h); + } + } + } + + fn replay_keys(inserts: &[H256], backing: &Database, refs: &mut HashMap) { + trace!(target: "jdb.fine", "replay_keys: inserts={:?}, refs={:?}", inserts, refs); + for h in inserts { + if let Some(c) = refs.get_mut(h) { + // already counting. increment. + c.queue_refs += 1; + continue; + } + + // this is the first entry for this node in the journal. + // it is initialised to 1 if it was already in. + refs.insert(h.clone(), RefInfo{queue_refs: 1, in_archive: Self::is_already_in(backing, h)}); + } + trace!(target: "jdb.fine", "replay_keys: (end) refs={:?}", refs); + } + + fn kill_keys(deletes: &[H256], refs: &mut HashMap, batch: &DBTransaction, from: RemoveFrom, trace: bool) { + // with a kill on {queue_refs: 1, in_archive: true}, we have two options: + // - convert to {queue_refs: 1, in_archive: false} (i.e. remove it from the conceptual archive) + // - convert to {queue_refs: 0, in_archive: true} (i.e. remove it from the conceptual queue) + // (the latter option would then mean removing the RefInfo, since it would no longer be counted in the queue.) + // both are valid, but we switch between them depending on context. + // All inserts in queue (i.e. those which may yet be reverted) have an entry in refs. + for h in deletes.iter() { + let mut n: Option = None; + if let Some(c) = refs.get_mut(h) { + if c.in_archive && from == RemoveFrom::Archive { + c.in_archive = false; + Self::reset_already_in(batch, h); + if trace { + trace!(target: "jdb.fine", " kill({}): In archive, 1 in queue: Reducing to queue only and recording", h); + } + continue; + } else if c.queue_refs > 1 { + c.queue_refs -= 1; + if trace { + trace!(target: "jdb.fine", " kill({}): In queue > 1 refs: Decrementing ref count to {}", h, c.queue_refs); + } + continue; + } else { + n = Some(c.clone()); + } + } + match n { + Some(RefInfo{queue_refs: 1, in_archive: true}) => { + refs.remove(h); + Self::reset_already_in(batch, h); + if trace { + trace!(target: "jdb.fine", " kill({}): In archive, 1 in queue: Removing from queue and leaving in archive", h); + } + } + Some(RefInfo{queue_refs: 1, in_archive: false}) => { + refs.remove(h); + batch.delete(&h.bytes()).expect("Low-level database error. Some issue with your hard disk?"); + if trace { + trace!(target: "jdb.fine", " kill({}): Not in archive, only 1 ref in queue: Removing from queue and DB", h); + } + } + None => { + // Gets removed when moving from 1 to 0 additional refs. Should never be here at 0 additional refs. + //assert!(!Self::is_already_in(db, &h)); + batch.delete(&h.bytes()).expect("Low-level database error. Some issue with your hard disk?"); + if trace { + trace!(target: "jdb.fine", " kill({}): Not in queue - MUST BE IN ARCHIVE: Removing from DB", h); + } + } + _ => panic!("Invalid value in refs: {:?}", n), + } + } + } + + #[cfg(test)] + fn can_reconstruct_refs(&self) -> bool { + let (latest_era, reconstructed) = Self::read_refs(&self.backing); + let refs = self.refs.as_ref().unwrap().write().unwrap(); + if *refs != reconstructed || latest_era != self.latest_era { + let clean_refs = refs.iter().filter_map(|(k, v)| if reconstructed.get(k) == Some(v) {None} else {Some((k.clone(), v.clone()))}).collect::>(); + let clean_recon = reconstructed.into_iter().filter_map(|(k, v)| if refs.get(&k) == Some(&v) {None} else {Some((k.clone(), v.clone()))}).collect::>(); + warn!(target: "jdb", "mem: {:?} != log: {:?}", clean_refs, clean_recon); + false + } else { + true + } + } + + fn payload(&self, key: &H256) -> Option { + self.backing.get(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?").map(|v| v.to_vec()) + } + + fn read_refs(db: &Database) -> (Option, HashMap) { + let mut refs = HashMap::new(); + let mut latest_era = None; + if let Some(val) = db.get(&LATEST_ERA_KEY).expect("Low-level database error.") { + let mut era = decode::(&val); + latest_era = Some(era); + loop { + let mut index = 0usize; + while let Some(rlp_data) = db.get({ + let mut r = RlpStream::new_list(3); + r.append(&era); + r.append(&index); + r.append(&&PADDING[..]); + &r.drain() + }).expect("Low-level database error.") { + let rlp = Rlp::new(&rlp_data); + let inserts: Vec = rlp.val_at(1); + Self::replay_keys(&inserts, db, &mut refs); + index += 1; + }; + if index == 0 || era == 0 { + break; + } + era -= 1; + } + } + (latest_era, refs) + } + } + +impl HashDB for EarlyMergeDB { + fn keys(&self) -> HashMap { + let mut ret: HashMap = HashMap::new(); + for (key, _) in self.backing.iter() { + let h = H256::from_slice(key.deref()); + ret.insert(h, 1); + } + + for (key, refs) in self.overlay.keys().into_iter() { + let refs = *ret.get(&key).unwrap_or(&0) + refs; + ret.insert(key, refs); + } + ret + } + + fn lookup(&self, key: &H256) -> Option<&[u8]> { + let k = self.overlay.raw(key); + match k { + Some(&(ref d, rc)) if rc > 0 => Some(d), + _ => { + if let Some(x) = self.payload(key) { + Some(&self.overlay.denote(key, x).0) + } + else { + None + } + } + } + } + + fn exists(&self, key: &H256) -> bool { + self.lookup(key).is_some() + } + + fn insert(&mut self, value: &[u8]) -> H256 { + self.overlay.insert(value) + } + fn emplace(&mut self, key: H256, value: Bytes) { + self.overlay.emplace(key, value); + } + fn kill(&mut self, key: &H256) { + self.overlay.kill(key); + } +} + +impl JournalDB for EarlyMergeDB { + fn spawn(&self) -> Box { + Box::new(EarlyMergeDB { + overlay: MemoryDB::new(), + backing: self.backing.clone(), + refs: self.refs.clone(), + latest_era: self.latest_era.clone(), + }) + } + + fn is_empty(&self) -> bool { + self.backing.get(&LATEST_ERA_KEY).expect("Low level database error").is_none() + } + + fn mem_used(&self) -> usize { + self.overlay.mem_used() + match self.refs { + Some(ref c) => c.read().unwrap().heap_size_of_children(), + None => 0 + } + } + + + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] + fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { + // journal format: + // [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] + // [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] + // [era, n] => [ ... ] + + // TODO: store reclaim_period. + + // When we make a new commit, we make a journal of all blocks in the recent history and record + // all keys that were inserted and deleted. The journal is ordered by era; multiple commits can + // share the same era. This forms a data structure similar to a queue but whose items are tuples. + // By the time comes to remove a tuple from the queue (i.e. then the era passes from recent history + // into ancient history) then only one commit from the tuple is considered canonical. This commit + // is kept in the main backing database, whereas any others from the same era are reverted. + // + // It is possible that a key, properly available in the backing database be deleted and re-inserted + // in the recent history queue, yet have both operations in commits that are eventually non-canonical. + // To avoid the original, and still required, key from being deleted, we maintain a reference count + // which includes an original key, if any. + // + // The semantics of the `counter` are: + // insert key k: + // counter already contains k: count += 1 + // counter doesn't contain k: + // backing db contains k: count = 1 + // backing db doesn't contain k: insert into backing db, count = 0 + // delete key k: + // counter contains k (count is asserted to be non-zero): + // count > 1: counter -= 1 + // count == 1: remove counter + // count == 0: remove key from backing db + // counter doesn't contain k: remove key from backing db + // + // Practically, this means that for each commit block turning from recent to ancient we do the + // following: + // is_canonical: + // inserts: Ignored (left alone in the backing database). + // deletes: Enacted; however, recent history queue is checked for ongoing references. This is + // reduced as a preference to deletion from the backing database. + // !is_canonical: + // inserts: Reverted; however, recent history queue is checked for ongoing references. This is + // reduced as a preference to deletion from the backing database. + // deletes: Ignored (they were never inserted). + // + + // record new commit's details. + let mut refs = self.refs.as_ref().unwrap().write().unwrap(); + let batch = DBTransaction::new(); + let trace = false; + { + let mut index = 0usize; + let mut last; + + while try!(self.backing.get({ + let mut r = RlpStream::new_list(3); + r.append(&now); + r.append(&index); + r.append(&&PADDING[..]); + last = r.drain(); + &last + })).is_some() { + index += 1; + } + + let drained = self.overlay.drain(); + + if trace { + trace!(target: "jdb", "commit: #{} ({}), end era: {:?}", now, id, end); + } + + let removes: Vec = drained + .iter() + .filter_map(|(k, &(_, c))| if c < 0 {Some(k.clone())} else {None}) + .collect(); + let inserts: Vec<(H256, Bytes)> = drained + .into_iter() + .filter_map(|(k, (v, r))| if r > 0 { assert!(r == 1); Some((k, v)) } else { assert!(r >= -1); None }) + .collect(); + + + // TODO: check all removes are in the db. + + let mut r = RlpStream::new_list(3); + r.append(id); + + // Process the new inserts. + // We use the inserts for three things. For each: + // - we place into the backing DB or increment the counter if already in; + // - we note in the backing db that it was already in; + // - we write the key into our journal for this block; + + r.begin_list(inserts.len()); + inserts.iter().foreach(|&(k, _)| {r.append(&k);}); + r.append(&removes); + Self::insert_keys(&inserts, &self.backing, &mut refs, &batch, trace); + if trace { + let ins = inserts.iter().map(|&(k, _)| k).collect::>(); + trace!(target: "jdb.ops", " Inserts: {:?}", ins); + trace!(target: "jdb.ops", " Deletes: {:?}", removes); + } + try!(batch.put(&last, r.as_raw())); + if self.latest_era.map_or(true, |e| now > e) { + try!(batch.put(&LATEST_ERA_KEY, &encode(&now))); + self.latest_era = Some(now); + } + } + + // apply old commits' details + if let Some((end_era, canon_id)) = end { + let mut index = 0usize; + let mut last; + while let Some(rlp_data) = try!(self.backing.get({ + let mut r = RlpStream::new_list(3); + r.append(&end_era); + r.append(&index); + r.append(&&PADDING[..]); + last = r.drain(); + &last + })) { + let rlp = Rlp::new(&rlp_data); + let inserts: Vec = rlp.val_at(1); + + if canon_id == rlp.val_at(0) { + // Collect keys to be removed. Canon block - remove the (enacted) deletes. + let deletes: Vec = rlp.val_at(2); + if trace { + trace!(target: "jdb.ops", " Expunging: {:?}", deletes); + } + Self::kill_keys(&deletes, &mut refs, &batch, RemoveFrom::Archive, trace); + + if trace { + trace!(target: "jdb.ops", " Finalising: {:?}", inserts); + } + for k in &inserts { + match refs.get(k).cloned() { + None => { + // [in archive] -> SHIFT remove -> SHIFT insert None->Some{queue_refs: 1, in_archive: true} -> TAKE remove Some{queue_refs: 1, in_archive: true}->None -> TAKE insert + // already expunged from the queue (which is allowed since the key is in the archive). + // leave well alone. + } + Some( RefInfo{queue_refs: 1, in_archive: false} ) => { + // just delete the refs entry. + refs.remove(k); + } + Some( RefInfo{queue_refs: x, in_archive: false} ) => { + // must set already in; , + Self::set_already_in(&batch, k); + refs.insert(k.clone(), RefInfo{ queue_refs: x - 1, in_archive: true }); + } + Some( RefInfo{in_archive: true, ..} ) => { + // Invalid! Reinserted the same key twice. + warn!("Key {} inserted twice into same fork.", k); + } + } + } + } else { + // Collect keys to be removed. Non-canon block - remove the (reverted) inserts. + if trace { + trace!(target: "jdb.ops", " Reverting: {:?}", inserts); + } + Self::kill_keys(&inserts, &mut refs, &batch, RemoveFrom::Queue, trace); + } + + try!(batch.delete(&last)); + index += 1; + } + if trace { + trace!(target: "jdb", "EarlyMergeDB: delete journal for time #{}.{}, (canon was {})", end_era, index, canon_id); + } + } + + try!(self.backing.write(batch)); + + // Comment out for now. TODO: automatically enable in tests. + + if trace { + trace!(target: "jdb", "OK: {:?}", refs.clone()); + } + + Ok(0) + } +} + +#[cfg(test)] +mod tests { + #![cfg_attr(feature="dev", allow(blacklisted_name))] + + use common::*; + use super::*; + use super::super::traits::JournalDB; + use hashdb::*; + use log::init_log; + + #[test] + fn insert_same_in_fork() { + // history is 1 + let mut jdb = EarlyMergeDB::new_temp(); + + let x = jdb.insert(b"X"); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(2, &b"2".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(3, &b"1002a".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(4, &b"1003a".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&x); + jdb.commit(3, &b"1002b".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + let x = jdb.insert(b"X"); + jdb.commit(4, &b"1003b".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.commit(5, &b"1004a".sha3(), Some((3, b"1002a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(6, &b"1005a".sha3(), Some((4, b"1003a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + assert!(jdb.exists(&x)); + } + + #[test] + fn insert_older_era() { + let mut jdb = EarlyMergeDB::new_temp(); + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0a".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + let bar = jdb.insert(b"bar"); + jdb.commit(1, &b"1".sha3(), Some((0, b"0a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&bar); + jdb.commit(0, &b"0b".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + } + + #[test] + fn long_history() { + // history is 3 + let mut jdb = EarlyMergeDB::new_temp(); + let h = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&h)); + jdb.remove(&h); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&h)); + jdb.commit(2, &b"2".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&h)); + jdb.commit(3, &b"3".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&h)); + jdb.commit(4, &b"4".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(!jdb.exists(&h)); + } + + #[test] + fn complex() { + // history is 1 + let mut jdb = EarlyMergeDB::new_temp(); + + let foo = jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + + jdb.remove(&foo); + jdb.remove(&bar); + let baz = jdb.insert(b"baz"); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + assert!(jdb.exists(&baz)); + + let foo = jdb.insert(b"foo"); + jdb.remove(&baz); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + assert!(!jdb.exists(&bar)); + assert!(jdb.exists(&baz)); + + jdb.remove(&foo); + jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + assert!(!jdb.exists(&bar)); + assert!(!jdb.exists(&baz)); + + jdb.commit(4, &b"4".sha3(), Some((3, b"3".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(!jdb.exists(&foo)); + assert!(!jdb.exists(&bar)); + assert!(!jdb.exists(&baz)); + } + + #[test] + fn fork() { + // history is 1 + let mut jdb = EarlyMergeDB::new_temp(); + + let foo = jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + + jdb.remove(&foo); + let baz = jdb.insert(b"baz"); + jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&bar); + jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + assert!(jdb.exists(&baz)); + + jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + assert!(!jdb.exists(&baz)); + assert!(!jdb.exists(&bar)); + } + + #[test] + fn overwrite() { + // history is 1 + let mut jdb = EarlyMergeDB::new_temp(); + + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + + jdb.remove(&foo); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.insert(b"foo"); + assert!(jdb.exists(&foo)); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + jdb.commit(3, &b"2".sha3(), Some((0, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + } + + #[test] + fn fork_same_key_one() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + let foo = jdb.insert(b"foo"); + jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(1, &b"1c".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + assert!(jdb.exists(&foo)); + + jdb.commit(2, &b"2a".sha3(), Some((1, b"1a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + } + + #[test] + fn fork_same_key_other() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + let foo = jdb.insert(b"foo"); + jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(1, &b"1c".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + assert!(jdb.exists(&foo)); + + jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + } + + #[test] + fn fork_ins_del_ins() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + let foo = jdb.insert(b"foo"); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(2, &b"2a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(2, &b"2b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(3, &b"3a".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(3, &b"3b".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.commit(4, &b"4a".sha3(), Some((2, b"2a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.commit(5, &b"5a".sha3(), Some((3, b"3a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + } + + #[test] + fn reopen() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + let bar = H256::random(); + + let foo = { + let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); + // history is 1 + let foo = jdb.insert(b"foo"); + jdb.emplace(bar.clone(), b"bar".to_vec()); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + foo + }; + + { + let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); + jdb.remove(&foo); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + } + + { + let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(!jdb.exists(&foo)); + } + } + + #[test] + fn insert_delete_insert_delete_insert_expunge() { + init_log(); + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); + + // history is 4 + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.remove(&foo); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.insert(b"foo"); + jdb.commit(2, &b"2".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.remove(&foo); + jdb.commit(3, &b"3".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.insert(b"foo"); + jdb.commit(4, &b"4".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + // expunge foo + jdb.commit(5, &b"5".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + } + + #[test] + fn forked_insert_delete_insert_delete_insert_expunge() { + init_log(); + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); + + // history is 4 + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(1, &b"1a".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(1, &b"1b".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(2, &b"2a".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(2, &b"2b".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(3, &b"3a".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(3, &b"3b".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(4, &b"4a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(4, &b"4b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + // expunge foo + jdb.commit(5, &b"5".sha3(), Some((1, b"1a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + } + + #[test] + fn broken_assert() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); + // history is 1 + let foo = jdb.insert(b"foo"); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + // foo is ancient history. + + jdb.remove(&foo); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); // BROKEN + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + + jdb.remove(&foo); + jdb.commit(4, &b"4".sha3(), Some((3, b"3".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.commit(5, &b"5".sha3(), Some((4, b"4".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(!jdb.exists(&foo)); + } + + #[test] + fn reopen_test() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); + // history is 4 + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(2, &b"2".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(3, &b"3".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(4, &b"4".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + // foo is ancient history. + + jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(5, &b"5".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.remove(&foo); + jdb.remove(&bar); + jdb.commit(6, &b"6".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.insert(b"foo"); + jdb.insert(b"bar"); + jdb.commit(7, &b"7".sha3(), Some((3, b"3".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + } + + #[test] + fn reopen_remove_three() { + init_log(); + + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let foo = b"foo".sha3(); + + { + let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); + // history is 1 + jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + // foo is ancient history. + + jdb.remove(&foo); + jdb.commit(2, &b"2".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + + jdb.insert(b"foo"); + jdb.commit(3, &b"3".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + + // incantation to reopen the db + }; { let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); + + jdb.remove(&foo); + jdb.commit(4, &b"4".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + + // incantation to reopen the db + }; { let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); + + jdb.commit(5, &b"5".sha3(), Some((3, b"3".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + + // incantation to reopen the db + }; { let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); + + jdb.commit(6, &b"6".sha3(), Some((4, b"4".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(!jdb.exists(&foo)); + } + } + + #[test] + fn reopen_fork() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + let (foo, bar, baz) = { + let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); + // history is 1 + let foo = jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.remove(&foo); + let baz = jdb.insert(b"baz"); + jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&bar); + jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + (foo, bar, baz) + }; + + { + let mut jdb = EarlyMergeDB::new(dir.to_str().unwrap()); + jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + assert!(!jdb.exists(&baz)); + assert!(!jdb.exists(&bar)); + } + } +} diff --git a/util/src/journaldb/mod.rs b/util/src/journaldb/mod.rs new file mode 100644 index 000000000..e73c12969 --- /dev/null +++ b/util/src/journaldb/mod.rs @@ -0,0 +1,81 @@ +// 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 . + +//! JournalDB interface and implementation. + +use common::*; + +/// Export the journaldb module. +pub mod traits; +mod archivedb; +mod earlymergedb; +mod overlayrecentdb; +mod refcounteddb; + +/// Export the JournalDB trait. +pub use self::traits::JournalDB; + +/// A journal database algorithm. +#[derive(Debug)] +pub enum Algorithm { + /// Keep all keys forever. + Archive, + + /// Ancient and recent history maintained separately; recent history lasts for particular + /// number of blocks. + /// + /// Inserts go into backing database, journal retains knowledge of whether backing DB key is + /// ancient or recent. Non-canon inserts get explicitly reverted and removed from backing DB. + EarlyMerge, + + /// Ancient and recent history maintained separately; recent history lasts for particular + /// number of blocks. + /// + /// Inserts go into memory overlay, which is tried for key fetches. Memory overlay gets + /// flushed in backing only at end of recent history. + OverlayRecent, + + /// Ancient and recent history maintained separately; recent history lasts for particular + /// number of blocks. + /// + /// References are counted in disk-backed DB. + RefCounted, +} + +impl Default for Algorithm { + fn default() -> Algorithm { Algorithm::Archive } +} + +impl fmt::Display for Algorithm { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", match self { + &Algorithm::Archive => "archive", + &Algorithm::EarlyMerge => "earlymerge", + &Algorithm::OverlayRecent => "overlayrecent", + &Algorithm::RefCounted => "refcounted", + }) + } +} + +/// Create a new JournalDB trait object. +pub fn new(path: &str, algorithm: Algorithm) -> Box { + match algorithm { + Algorithm::Archive => Box::new(archivedb::ArchiveDB::new(path)), + Algorithm::EarlyMerge => Box::new(earlymergedb::EarlyMergeDB::new(path)), + Algorithm::OverlayRecent => Box::new(overlayrecentdb::OverlayRecentDB::new(path)), + Algorithm::RefCounted => Box::new(refcounteddb::RefCountedDB::new(path)), + } +} diff --git a/util/src/journaldb/overlayrecentdb.rs b/util/src/journaldb/overlayrecentdb.rs new file mode 100644 index 000000000..102e23407 --- /dev/null +++ b/util/src/journaldb/overlayrecentdb.rs @@ -0,0 +1,895 @@ +// 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 . + +//! JournalDB over in-memory overlay + +use common::*; +use rlp::*; +use hashdb::*; +use memorydb::*; +use kvdb::{Database, DBTransaction, DatabaseConfig}; +#[cfg(test)] +use std::env; +use super::JournalDB; + +/// Implementation of the JournalDB trait for a disk-backed database with a memory overlay +/// and, possibly, latent-removal semantics. +/// +/// 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. +/// +/// There are two memory overlays: +/// - Transaction overlay contains current transaction data. It is merged with with history +/// overlay on each `commit()` +/// - History overlay contains all data inserted during the history period. When the node +/// in the overlay becomes ancient it is written to disk on `commit()` +/// +/// There is also a journal maintained in memory and on the disk as well which lists insertions +/// and removals for each commit during the history period. This is used to track +/// data nodes that go out of history scope and must be written to disk. +/// +/// Commit workflow: +/// 1. Create a new journal record from the transaction overlay. +/// 2. Inseart each node from the transaction overlay into the History overlay increasing reference +/// count if it is already there. Note that the reference counting is managed by `MemoryDB` +/// 3. Clear the transaction overlay. +/// 4. For a canonical journal record that becomes ancient inserts its insertions into the disk DB +/// 5. For each journal record that goes out of the history scope (becomes ancient) remove its +/// insertions from the history overlay, decreasing the reference counter and removing entry if +/// if reaches zero. +/// 6. For a canonical journal record that becomes ancient delete its removals from the disk only if +/// the removed key is not present in the history overlay. +/// 7. Delete ancient record from memory and disk. + +pub struct OverlayRecentDB { + transaction_overlay: MemoryDB, + backing: Arc, + journal_overlay: Arc>, +} + +#[derive(PartialEq)] +struct JournalOverlay { + backing_overlay: MemoryDB, + journal: HashMap>, + latest_era: Option, +} + +#[derive(PartialEq)] +struct JournalEntry { + id: H256, + insertions: Vec, + deletions: Vec, +} + +impl HeapSizeOf for JournalEntry { + fn heap_size_of_children(&self) -> usize { + self.insertions.heap_size_of_children() + self.deletions.heap_size_of_children() + } +} + +impl Clone for OverlayRecentDB { + fn clone(&self) -> OverlayRecentDB { + OverlayRecentDB { + transaction_overlay: MemoryDB::new(), + backing: self.backing.clone(), + journal_overlay: self.journal_overlay.clone(), + } + } +} + +// all keys must be at least 12 bytes +const LATEST_ERA_KEY : [u8; 12] = [ b'l', b'a', b's', b't', 0, 0, 0, 0, 0, 0, 0, 0 ]; +const VERSION_KEY : [u8; 12] = [ b'j', b'v', b'e', b'r', 0, 0, 0, 0, 0, 0, 0, 0 ]; +const DB_VERSION : u32 = 0x200 + 3; +const PADDING : [u8; 10] = [ 0u8; 10 ]; + +impl OverlayRecentDB { + /// Create a new instance from file + pub fn new(path: &str) -> OverlayRecentDB { + Self::from_prefs(path) + } + + /// Create a new instance from file + pub fn from_prefs(path: &str) -> OverlayRecentDB { + let opts = DatabaseConfig { + prefix_size: Some(12) //use 12 bytes as prefix, this must match account_db prefix + }; + let backing = Database::open(&opts, path).unwrap_or_else(|e| { + panic!("Error opening state db: {}", e); + }); + if !backing.is_empty() { + match backing.get(&VERSION_KEY).map(|d| d.map(|v| decode::(&v))) { + Ok(Some(DB_VERSION)) => {} + v => panic!("Incompatible DB version, expected {}, got {:?}", DB_VERSION, v) + } + } else { + backing.put(&VERSION_KEY, &encode(&DB_VERSION)).expect("Error writing version to database"); + } + + let journal_overlay = Arc::new(RwLock::new(OverlayRecentDB::read_overlay(&backing))); + OverlayRecentDB { + transaction_overlay: MemoryDB::new(), + backing: Arc::new(backing), + journal_overlay: journal_overlay, + } + } + + /// Create a new instance with an anonymous temporary database. + #[cfg(test)] + pub fn new_temp() -> OverlayRecentDB { + let mut dir = env::temp_dir(); + dir.push(H32::random().hex()); + Self::new(dir.to_str().unwrap()) + } + + #[cfg(test)] + fn can_reconstruct_refs(&self) -> bool { + let reconstructed = Self::read_overlay(&self.backing); + let journal_overlay = self.journal_overlay.read().unwrap(); + *journal_overlay == reconstructed + } + + fn payload(&self, key: &H256) -> Option { + self.backing.get(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?").map(|v| v.to_vec()) + } + + fn read_overlay(db: &Database) -> JournalOverlay { + let mut journal = HashMap::new(); + let mut overlay = MemoryDB::new(); + let mut count = 0; + let mut latest_era = None; + if let Some(val) = db.get(&LATEST_ERA_KEY).expect("Low-level database error.") { + let mut era = decode::(&val); + latest_era = Some(era); + loop { + let mut index = 0usize; + while let Some(rlp_data) = db.get({ + let mut r = RlpStream::new_list(3); + r.append(&era); + r.append(&index); + r.append(&&PADDING[..]); + &r.drain() + }).expect("Low-level database error.") { + trace!("read_overlay: era={}, index={}", era, index); + let rlp = Rlp::new(&rlp_data); + let id: H256 = rlp.val_at(0); + let insertions = rlp.at(1); + let deletions: Vec = rlp.val_at(2); + let mut inserted_keys = Vec::new(); + for r in insertions.iter() { + let k: H256 = r.val_at(0); + let v: Bytes = r.val_at(1); + overlay.emplace(k.clone(), v); + inserted_keys.push(k); + count += 1; + } + journal.entry(era).or_insert_with(Vec::new).push(JournalEntry { + id: id, + insertions: inserted_keys, + deletions: deletions, + }); + index += 1; + }; + if index == 0 || era == 0 { + break; + } + era -= 1; + } + } + trace!("Recovered {} overlay entries, {} journal entries", count, journal.len()); + JournalOverlay { backing_overlay: overlay, journal: journal, latest_era: latest_era } + } +} + +impl JournalDB for OverlayRecentDB { + fn spawn(&self) -> Box { + Box::new(self.clone()) + } + + fn mem_used(&self) -> usize { + let mut mem = self.transaction_overlay.mem_used(); + let overlay = self.journal_overlay.read().unwrap(); + mem += overlay.backing_overlay.mem_used(); + mem += overlay.journal.heap_size_of_children(); + mem + } + + fn is_empty(&self) -> bool { + self.backing.get(&LATEST_ERA_KEY).expect("Low level database error").is_none() + } + + fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { + // record new commit's details. + trace!("commit: #{} ({}), end era: {:?}", now, id, end); + let mut journal_overlay = self.journal_overlay.write().unwrap(); + let batch = DBTransaction::new(); + { + let mut r = RlpStream::new_list(3); + let mut tx = self.transaction_overlay.drain(); + let inserted_keys: Vec<_> = tx.iter().filter_map(|(k, &(_, c))| if c > 0 { Some(k.clone()) } else { None }).collect(); + let removed_keys: Vec<_> = tx.iter().filter_map(|(k, &(_, c))| if c < 0 { Some(k.clone()) } else { None }).collect(); + // Increase counter for each inserted key no matter if the block is canonical or not. + let insertions = tx.drain().filter_map(|(k, (v, c))| if c > 0 { Some((k, v)) } else { None }); + r.append(id); + r.begin_list(inserted_keys.len()); + for (k, v) in insertions { + r.begin_list(2); + r.append(&k); + r.append(&v); + journal_overlay.backing_overlay.emplace(k, v); + } + r.append(&removed_keys); + + let mut k = RlpStream::new_list(3); + let index = journal_overlay.journal.get(&now).map_or(0, |j| j.len()); + k.append(&now); + k.append(&index); + k.append(&&PADDING[..]); + try!(batch.put(&k.drain(), r.as_raw())); + if journal_overlay.latest_era.map_or(true, |e| now > e) { + try!(batch.put(&LATEST_ERA_KEY, &encode(&now))); + journal_overlay.latest_era = Some(now); + } + journal_overlay.journal.entry(now).or_insert_with(Vec::new).push(JournalEntry { id: id.clone(), insertions: inserted_keys, deletions: removed_keys }); + } + + let journal_overlay = journal_overlay.deref_mut(); + // apply old commits' details + if let Some((end_era, canon_id)) = end { + if let Some(ref mut records) = journal_overlay.journal.get_mut(&end_era) { + let mut canon_insertions: Vec<(H256, Bytes)> = Vec::new(); + let mut canon_deletions: Vec = Vec::new(); + let mut overlay_deletions: Vec = Vec::new(); + let mut index = 0usize; + for mut journal in records.drain(..) { + //delete the record from the db + let mut r = RlpStream::new_list(3); + r.append(&end_era); + r.append(&index); + r.append(&&PADDING[..]); + try!(batch.delete(&r.drain())); + trace!("commit: Delete journal for time #{}.{}: {}, (canon was {}): +{} -{} entries", end_era, index, journal.id, canon_id, journal.insertions.len(), journal.deletions.len()); + { + if canon_id == journal.id { + for h in &journal.insertions { + if let Some(&(ref d, rc)) = journal_overlay.backing_overlay.raw(h) { + if rc > 0 { + canon_insertions.push((h.clone(), d.clone())); //TODO: optimize this to avoid data copy + } + } + } + canon_deletions = journal.deletions; + } + overlay_deletions.append(&mut journal.insertions); + } + index += 1; + } + // apply canon inserts first + for (k, v) in canon_insertions { + try!(batch.put(&k, &v)); + } + // update the overlay + for k in overlay_deletions { + journal_overlay.backing_overlay.kill(&k); + } + // apply canon deletions + for k in canon_deletions { + if !journal_overlay.backing_overlay.exists(&k) { + try!(batch.delete(&k)); + } + } + journal_overlay.backing_overlay.purge(); + } + journal_overlay.journal.remove(&end_era); + } + try!(self.backing.write(batch)); + Ok(0) + } + +} + +impl HashDB for OverlayRecentDB { + fn keys(&self) -> HashMap { + let mut ret: HashMap = HashMap::new(); + for (key, _) in self.backing.iter() { + let h = H256::from_slice(key.deref()); + ret.insert(h, 1); + } + + for (key, refs) in self.transaction_overlay.keys().into_iter() { + let refs = *ret.get(&key).unwrap_or(&0) + refs; + ret.insert(key, refs); + } + ret + } + + fn lookup(&self, key: &H256) -> Option<&[u8]> { + let k = self.transaction_overlay.raw(key); + match k { + Some(&(ref d, rc)) if rc > 0 => Some(d), + _ => { + let v = self.journal_overlay.read().unwrap().backing_overlay.lookup(key).map(|v| v.to_vec()); + match v { + Some(x) => { + Some(&self.transaction_overlay.denote(key, x).0) + } + _ => { + if let Some(x) = self.payload(key) { + Some(&self.transaction_overlay.denote(key, x).0) + } + else { + None + } + } + } + } + } + } + + fn exists(&self, key: &H256) -> bool { + self.lookup(key).is_some() + } + + fn insert(&mut self, value: &[u8]) -> H256 { + self.transaction_overlay.insert(value) + } + fn emplace(&mut self, key: H256, value: Bytes) { + self.transaction_overlay.emplace(key, value); + } + fn kill(&mut self, key: &H256) { + self.transaction_overlay.kill(key); + } +} + +#[cfg(test)] +mod tests { + #![cfg_attr(feature="dev", allow(blacklisted_name))] + + use common::*; + use super::*; + use hashdb::*; + use log::init_log; + use journaldb::JournalDB; + + #[test] + fn insert_same_in_fork() { + // history is 1 + let mut jdb = OverlayRecentDB::new_temp(); + + let x = jdb.insert(b"X"); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(2, &b"2".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(3, &b"1002a".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(4, &b"1003a".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&x); + jdb.commit(3, &b"1002b".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + let x = jdb.insert(b"X"); + jdb.commit(4, &b"1003b".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.commit(5, &b"1004a".sha3(), Some((3, b"1002a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(6, &b"1005a".sha3(), Some((4, b"1003a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + assert!(jdb.exists(&x)); + } + + #[test] + fn long_history() { + // history is 3 + let mut jdb = OverlayRecentDB::new_temp(); + let h = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&h)); + jdb.remove(&h); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&h)); + jdb.commit(2, &b"2".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&h)); + jdb.commit(3, &b"3".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&h)); + jdb.commit(4, &b"4".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(!jdb.exists(&h)); + } + + #[test] + fn complex() { + // history is 1 + let mut jdb = OverlayRecentDB::new_temp(); + + let foo = jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + + jdb.remove(&foo); + jdb.remove(&bar); + let baz = jdb.insert(b"baz"); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + assert!(jdb.exists(&baz)); + + let foo = jdb.insert(b"foo"); + jdb.remove(&baz); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + assert!(!jdb.exists(&bar)); + assert!(jdb.exists(&baz)); + + jdb.remove(&foo); + jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + assert!(!jdb.exists(&bar)); + assert!(!jdb.exists(&baz)); + + jdb.commit(4, &b"4".sha3(), Some((3, b"3".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(!jdb.exists(&foo)); + assert!(!jdb.exists(&bar)); + assert!(!jdb.exists(&baz)); + } + + #[test] + fn fork() { + // history is 1 + let mut jdb = OverlayRecentDB::new_temp(); + + let foo = jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + + jdb.remove(&foo); + let baz = jdb.insert(b"baz"); + jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&bar); + jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + assert!(jdb.exists(&baz)); + + jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + assert!(!jdb.exists(&baz)); + assert!(!jdb.exists(&bar)); + } + + #[test] + fn overwrite() { + // history is 1 + let mut jdb = OverlayRecentDB::new_temp(); + + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + + jdb.remove(&foo); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.insert(b"foo"); + assert!(jdb.exists(&foo)); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + jdb.commit(3, &b"2".sha3(), Some((0, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + } + + #[test] + fn fork_same_key_one() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + let foo = jdb.insert(b"foo"); + jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(1, &b"1c".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + assert!(jdb.exists(&foo)); + + jdb.commit(2, &b"2a".sha3(), Some((1, b"1a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + } + + #[test] + fn fork_same_key_other() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + let foo = jdb.insert(b"foo"); + jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(1, &b"1c".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + assert!(jdb.exists(&foo)); + + jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + } + + #[test] + fn fork_ins_del_ins() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + let foo = jdb.insert(b"foo"); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(2, &b"2a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(2, &b"2b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(3, &b"3a".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(3, &b"3b".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.commit(4, &b"4a".sha3(), Some((2, b"2a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.commit(5, &b"5a".sha3(), Some((3, b"3a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + } + + #[test] + fn reopen() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + let bar = H256::random(); + + let foo = { + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); + // history is 1 + let foo = jdb.insert(b"foo"); + jdb.emplace(bar.clone(), b"bar".to_vec()); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + foo + }; + + { + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); + jdb.remove(&foo); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + } + + { + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(!jdb.exists(&foo)); + } + } + + #[test] + fn insert_delete_insert_delete_insert_expunge() { + init_log(); + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); + + // history is 4 + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.remove(&foo); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.insert(b"foo"); + jdb.commit(2, &b"2".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.remove(&foo); + jdb.commit(3, &b"3".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.insert(b"foo"); + jdb.commit(4, &b"4".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + // expunge foo + jdb.commit(5, &b"5".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + } + + #[test] + fn forked_insert_delete_insert_delete_insert_expunge() { + init_log(); + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); + + // history is 4 + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(1, &b"1a".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(1, &b"1b".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(2, &b"2a".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(2, &b"2b".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(3, &b"3a".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&foo); + jdb.commit(3, &b"3b".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(4, &b"4a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(4, &b"4b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + // expunge foo + jdb.commit(5, &b"5".sha3(), Some((1, b"1a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + } + + #[test] + fn broken_assert() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); + // history is 1 + let foo = jdb.insert(b"foo"); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + // foo is ancient history. + + jdb.remove(&foo); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.insert(b"foo"); + jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); // BROKEN + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + + jdb.remove(&foo); + jdb.commit(4, &b"4".sha3(), Some((3, b"3".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.commit(5, &b"5".sha3(), Some((4, b"4".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(!jdb.exists(&foo)); + } + + #[test] + fn reopen_test() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); + // history is 4 + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(2, &b"2".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(3, &b"3".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(4, &b"4".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + // foo is ancient history. + + jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(5, &b"5".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.remove(&foo); + jdb.remove(&bar); + jdb.commit(6, &b"6".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.insert(b"foo"); + jdb.insert(b"bar"); + jdb.commit(7, &b"7".sha3(), Some((3, b"3".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + } + + #[test] + fn reopen_remove_three() { + init_log(); + + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let foo = b"foo".sha3(); + + { + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); + // history is 1 + jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + // foo is ancient history. + + jdb.remove(&foo); + jdb.commit(2, &b"2".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + + jdb.insert(b"foo"); + jdb.commit(3, &b"3".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + + // incantation to reopen the db + }; { let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); + + jdb.remove(&foo); + jdb.commit(4, &b"4".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + + // incantation to reopen the db + }; { let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); + + jdb.commit(5, &b"5".sha3(), Some((3, b"3".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + + // incantation to reopen the db + }; { let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); + + jdb.commit(6, &b"6".sha3(), Some((4, b"4".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(!jdb.exists(&foo)); + } + } + + #[test] + fn reopen_fork() { + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + let (foo, bar, baz) = { + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); + // history is 1 + let foo = jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.remove(&foo); + let baz = jdb.insert(b"baz"); + jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&bar); + jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + (foo, bar, baz) + }; + + { + let mut jdb = OverlayRecentDB::new(dir.to_str().unwrap()); + jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + assert!(jdb.exists(&foo)); + assert!(!jdb.exists(&baz)); + assert!(!jdb.exists(&bar)); + } + } + + #[test] + fn insert_older_era() { + let mut jdb = OverlayRecentDB::new_temp(); + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0a".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + let bar = jdb.insert(b"bar"); + jdb.commit(1, &b"1".sha3(), Some((0, b"0a".sha3()))).unwrap(); + assert!(jdb.can_reconstruct_refs()); + + jdb.remove(&bar); + jdb.commit(0, &b"0b".sha3(), None).unwrap(); + assert!(jdb.can_reconstruct_refs()); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + } +} diff --git a/util/src/journaldb/refcounteddb.rs b/util/src/journaldb/refcounteddb.rs new file mode 100644 index 000000000..a8c3ff12b --- /dev/null +++ b/util/src/journaldb/refcounteddb.rs @@ -0,0 +1,287 @@ +// 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 . + +//! Disk-backed, ref-counted JournalDB implementation. + +use common::*; +use rlp::*; +use hashdb::*; +use overlaydb::*; +use super::traits::JournalDB; +use kvdb::{Database, DBTransaction, DatabaseConfig}; +#[cfg(test)] +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 +/// 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. +pub struct RefCountedDB { + forward: OverlayDB, + backing: Arc, + latest_era: Option, + inserts: Vec, + removes: Vec, +} + +const LATEST_ERA_KEY : [u8; 12] = [ b'l', b'a', b's', b't', 0, 0, 0, 0, 0, 0, 0, 0 ]; +const VERSION_KEY : [u8; 12] = [ b'j', b'v', b'e', b'r', 0, 0, 0, 0, 0, 0, 0, 0 ]; +const DB_VERSION : u32 = 512; +const PADDING : [u8; 10] = [ 0u8; 10 ]; + +impl RefCountedDB { + /// Create a new instance given a `backing` database. + pub fn new(path: &str) -> RefCountedDB { + let opts = DatabaseConfig { + prefix_size: Some(12) //use 12 bytes as prefix, this must match account_db prefix + }; + let backing = Database::open(&opts, path).unwrap_or_else(|e| { + panic!("Error opening state db: {}", e); + }); + if !backing.is_empty() { + match backing.get(&VERSION_KEY).map(|d| d.map(|v| decode::(&v))) { + Ok(Some(DB_VERSION)) => {}, + v => panic!("Incompatible DB version, expected {}, got {:?}", DB_VERSION, v) + } + } else { + backing.put(&VERSION_KEY, &encode(&DB_VERSION)).expect("Error writing version to database"); + } + + let backing = Arc::new(backing); + let latest_era = backing.get(&LATEST_ERA_KEY).expect("Low-level database error.").map(|val| decode::(&val)); + + RefCountedDB { + forward: OverlayDB::new_with_arc(backing.clone()), + backing: backing, + inserts: vec![], + removes: vec![], + latest_era: latest_era, + } + } + + /// Create a new instance with an anonymous temporary database. + #[cfg(test)] + fn new_temp() -> RefCountedDB { + let mut dir = env::temp_dir(); + dir.push(H32::random().hex()); + Self::new(dir.to_str().unwrap()) + } +} + +impl HashDB for RefCountedDB { + fn keys(&self) -> HashMap { self.forward.keys() } + fn lookup(&self, key: &H256) -> Option<&[u8]> { self.forward.lookup(key) } + fn exists(&self, key: &H256) -> bool { self.forward.exists(key) } + fn insert(&mut self, value: &[u8]) -> H256 { let r = self.forward.insert(value); self.inserts.push(r.clone()); r } + fn emplace(&mut self, key: H256, value: Bytes) { self.inserts.push(key.clone()); self.forward.emplace(key, value); } + fn kill(&mut self, key: &H256) { self.removes.push(key.clone()); } +} + +impl JournalDB for RefCountedDB { + fn spawn(&self) -> Box { + Box::new(RefCountedDB { + forward: self.forward.clone(), + backing: self.backing.clone(), + latest_era: self.latest_era, + inserts: self.inserts.clone(), + removes: self.removes.clone(), + }) + } + + fn mem_used(&self) -> usize { + self.inserts.heap_size_of_children() + self.removes.heap_size_of_children() + } + + fn is_empty(&self) -> bool { + self.latest_era.is_none() + } + + fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { + // journal format: + // [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] + // [era, 1] => [ id, [insert_0, ...], [remove_0, ...] ] + // [era, n] => [ ... ] + + // 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, + // we remove all of its removes assuming it is canonical and all + // of its inserts otherwise. + + // record new commit's details. + let batch = DBTransaction::new(); + { + let mut index = 0usize; + let mut last; + + while try!(self.backing.get({ + let mut r = RlpStream::new_list(3); + r.append(&now); + r.append(&index); + r.append(&&PADDING[..]); + last = r.drain(); + &last + })).is_some() { + index += 1; + } + + let mut r = RlpStream::new_list(3); + r.append(id); + 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(); + self.removes.clear(); + + if self.latest_era.map_or(true, |e| now > e) { + try!(batch.put(&LATEST_ERA_KEY, &encode(&now))); + self.latest_era = Some(now); + } + } + + // apply old commits' details + if let Some((end_era, canon_id)) = end { + let mut index = 0usize; + let mut last; + while let Some(rlp_data) = { +// trace!(target: "rcdb", "checking for journal #{}.{}", end_era, index); + try!(self.backing.get({ + let mut r = RlpStream::new_list(3); + r.append(&end_era); + r.append(&index); + r.append(&&PADDING[..]); + last = r.drain(); + &last + })) + } { + let rlp = Rlp::new(&rlp_data); + let our_id: H256 = rlp.val_at(0); + let to_remove: Vec = rlp.val_at(if canon_id == our_id {2} else {1}); + trace!(target: "rcdb", "delete journal for time #{}.{}=>{}, (canon was {}): deleting {:?}", end_era, index, our_id, canon_id, to_remove); + for i in &to_remove { + self.forward.remove(i); + } + try!(batch.delete(&last)); + index += 1; + } + } + + let r = try!(self.forward.commit_to_batch(&batch)); + try!(self.backing.write(batch)); + Ok(r) + } +} + +#[cfg(test)] +mod tests { + #![cfg_attr(feature="dev", allow(blacklisted_name))] + + use common::*; + use super::*; + use super::super::traits::JournalDB; + use hashdb::*; + + #[test] + fn long_history() { + // history is 3 + let mut jdb = RefCountedDB::new_temp(); + let h = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.exists(&h)); + jdb.remove(&h); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert!(jdb.exists(&h)); + jdb.commit(2, &b"2".sha3(), None).unwrap(); + assert!(jdb.exists(&h)); + jdb.commit(3, &b"3".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.exists(&h)); + jdb.commit(4, &b"4".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(!jdb.exists(&h)); + } + + #[test] + fn complex() { + // history is 1 + let mut jdb = RefCountedDB::new_temp(); + + let foo = jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + + jdb.remove(&foo); + jdb.remove(&bar); + let baz = jdb.insert(b"baz"); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + assert!(jdb.exists(&baz)); + + let foo = jdb.insert(b"foo"); + jdb.remove(&baz); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + assert!(!jdb.exists(&bar)); + assert!(jdb.exists(&baz)); + + jdb.remove(&foo); + jdb.commit(3, &b"3".sha3(), Some((2, b"2".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + assert!(!jdb.exists(&bar)); + assert!(!jdb.exists(&baz)); + + jdb.commit(4, &b"4".sha3(), Some((3, b"3".sha3()))).unwrap(); + assert!(!jdb.exists(&foo)); + assert!(!jdb.exists(&bar)); + assert!(!jdb.exists(&baz)); + } + + #[test] + fn fork() { + // history is 1 + let mut jdb = RefCountedDB::new_temp(); + + let foo = jdb.insert(b"foo"); + let bar = jdb.insert(b"bar"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + + jdb.remove(&foo); + let baz = jdb.insert(b"baz"); + jdb.commit(1, &b"1a".sha3(), Some((0, b"0".sha3()))).unwrap(); + + jdb.remove(&bar); + jdb.commit(1, &b"1b".sha3(), Some((0, b"0".sha3()))).unwrap(); + + assert!(jdb.exists(&foo)); + assert!(jdb.exists(&bar)); + assert!(jdb.exists(&baz)); + + jdb.commit(2, &b"2b".sha3(), Some((1, b"1b".sha3()))).unwrap(); + assert!(jdb.exists(&foo)); + assert!(!jdb.exists(&baz)); + assert!(!jdb.exists(&bar)); + } +} diff --git a/util/src/journaldb/traits.rs b/util/src/journaldb/traits.rs new file mode 100644 index 000000000..017c24330 --- /dev/null +++ b/util/src/journaldb/traits.rs @@ -0,0 +1,42 @@ +// 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 . + +//! Disk-backed HashDB implementation. + +use common::*; +use hashdb::*; + +/// A HashDB which can manage a short-term journal potentially containing many forks of mutually +/// exclusive actions. +pub trait JournalDB : HashDB + Send + Sync { + /// Return a copy of ourself, in a box. + fn spawn(&self) -> Box; + + /// Returns heap memory size used + fn mem_used(&self) -> usize; + + /// Check if this database has any commits + fn is_empty(&self) -> bool; + + /// Commit all recent insert operations and canonical historical commits' removals from the + /// old era to the backing database, reverting any non-canonical historical commit's inserts. + fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result; + + /// State data query + fn state(&self, _id: &H256) -> Option { + None + } +} diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index c5e17100f..a92bf4593 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -27,7 +27,7 @@ const MAX_CACHE_USAGE_TRACK: usize = 128; #[derive(PartialEq, Debug, Clone)] pub enum CryptoCipherType { /// aes-128-ctr with 128-bit initialisation vector(iv) - Aes128Ctr(U128) + Aes128Ctr(H128) } #[derive(PartialEq, Debug, Clone)] @@ -168,6 +168,8 @@ pub struct KeyFileCrypto { pub cipher_text: Bytes, /// Password derived key generator function settings. pub kdf: KeyFileKdf, + /// Mac + pub mac: H256 } impl KeyFileCrypto { @@ -182,7 +184,7 @@ impl KeyFileCrypto { Some("aes-128-ctr") => CryptoCipherType::Aes128Ctr( match try!(as_object.get("cipherparams").ok_or(CryptoParseError::NoCipherParameters)).as_object() { None => { return Err(CryptoParseError::NoCipherParameters); }, - Some(cipher_param) => match U128::from_str(match cipher_param["iv"].as_string() { + Some(cipher_param) => match H128::from_str(match cipher_param["iv"].as_string() { None => { return Err(CryptoParseError::NoInitialVector); }, Some(iv_hex_string) => iv_hex_string }) @@ -216,22 +218,31 @@ impl KeyFileCrypto { } }; - let cipher_text = match as_object["ciphertext"].as_string() { - None => { return Err(CryptoParseError::NoCipherText); } + let cipher_text = match try!(as_object.get("ciphertext").ok_or(CryptoParseError::NoCipherText)).as_string() { + None => { return Err(CryptoParseError::InvalidCipherText); } Some(text) => text }; + let mac: H256 = match try!(as_object.get("mac").ok_or(CryptoParseError::NoMac)).as_string() { + None => { return Err(CryptoParseError::InvalidMacFormat(None)) }, + Some(salt_value) => match H256::from_str(salt_value) { + Ok(salt_hex_value) => salt_hex_value, + Err(from_hex_error) => { return Err(CryptoParseError::InvalidMacFormat(Some(from_hex_error))); }, + } + }; + Ok(KeyFileCrypto { - cipher_text: Bytes::from(cipher_text), + cipher_text: match FromHex::from_hex(cipher_text) { Ok(bytes) => bytes, Err(_) => { return Err(CryptoParseError::InvalidCipherText); } }, cipher_type: cipher_type, kdf: kdf, + mac: mac, }) } fn to_json(&self) -> Json { let mut map = BTreeMap::new(); match self.cipher_type { - CryptoCipherType::Aes128Ctr(iv) => { + CryptoCipherType::Aes128Ctr(ref iv) => { map.insert("cipher".to_owned(), Json::String("aes-128-ctr".to_owned())); let mut cipher_params = BTreeMap::new(); cipher_params.insert("iv".to_owned(), Json::String(format!("{:?}", iv))); @@ -251,6 +262,8 @@ impl KeyFileCrypto { KeyFileKdf::Scrypt(ref scrypt_params) => scrypt_params.to_json() }); + map.insert("mac".to_owned(), Json::String(format!("{:?}", self.mac))); + Json::Object(map) } @@ -260,7 +273,7 @@ impl KeyFileCrypto { /// `c` - number of iterations for derived key. /// `salt` - cryptographic site, random 256-bit hash (ensure it's crypto-random). /// `iv` - initialisation vector. - pub fn new_pbkdf2(cipher_text: Bytes, iv: U128, salt: H256, c: u32, dk_len: u32) -> KeyFileCrypto { + pub fn new_pbkdf2(cipher_text: Bytes, iv: H128, salt: H256, mac: H256, c: u32, dk_len: u32) -> KeyFileCrypto { KeyFileCrypto { cipher_type: CryptoCipherType::Aes128Ctr(iv), cipher_text: cipher_text, @@ -270,6 +283,7 @@ impl KeyFileCrypto { c: c, prf: Pbkdf2CryptoFunction::HMacSha256 }), + mac: mac, } } } @@ -291,7 +305,7 @@ fn uuid_to_string(uuid: &Uuid) -> String { } fn uuid_from_string(s: &str) -> Result { - let parts: Vec<&str> = s.split("-").collect(); + let parts: Vec<&str> = s.split('-').collect(); if parts.len() != 5 { return Err(UtilError::BadSize); } let mut uuid = H128::zero(); @@ -319,19 +333,24 @@ pub struct KeyFileContent { /// Holds cypher and decrypt function settings. pub crypto: KeyFileCrypto, /// The identifier. - pub id: Uuid + pub id: Uuid, + /// Account (if present) + pub account: Option
, } #[derive(Debug)] enum CryptoParseError { + InvalidMacFormat(Option), + NoMac, NoCipherText, + InvalidCipherText, NoCipherType, InvalidJsonFormat, InvalidKdfType(Mismatch), InvalidCipherType(Mismatch), NoInitialVector, NoCipherParameters, - InvalidInitialVector(FromHexError), + InvalidInitialVector(UtilError), NoKdf, NoKdfType, Scrypt(ScryptParseError), @@ -357,7 +376,19 @@ impl KeyFileContent { KeyFileContent { id: new_uuid(), version: KeyFileVersion::V3(3), - crypto: crypto + crypto: crypto, + account: None + } + } + + /// Loads key from valid json, returns error and records warning if key is mallformed + pub fn load(json: &Json) -> Result { + match Self::from_json(json) { + Ok(key_file) => Ok(key_file), + Err(e) => { + warn!(target: "sstore", "Error parsing json for key: {:?}", e); + Err(()) + } } } @@ -390,6 +421,9 @@ impl KeyFileContent { Ok(id) => id }; + let account = as_object.get("address").and_then(|json| json.as_string()).and_then( + |account_text| match Address::from_str(account_text) { Ok(account) => Some(account), Err(_) => None }); + let crypto = match as_object.get("crypto") { None => { return Err(KeyFileParseError::NoCryptoSection); } Some(crypto_json) => match KeyFileCrypto::from_json(crypto_json) { @@ -401,7 +435,8 @@ impl KeyFileContent { Ok(KeyFileContent { version: version, id: id.clone(), - crypto: crypto + crypto: crypto, + account: account }) } @@ -410,6 +445,7 @@ impl KeyFileContent { map.insert("id".to_owned(), Json::String(uuid_to_string(&self.id))); map.insert("version".to_owned(), Json::U64(CURRENT_DECLARED_VERSION)); map.insert("crypto".to_owned(), self.crypto.to_json()); + if let Some(ref address) = self.account { map.insert("address".to_owned(), Json::String(format!("{:?}", address))); } Json::Object(map) } } @@ -425,17 +461,17 @@ enum KeyFileLoadError { pub struct KeyDirectory { /// Directory path for key management. path: String, - cache: HashMap, - cache_usage: VecDeque, + cache: RwLock>, + cache_usage: RwLock>, } impl KeyDirectory { /// Initializes new cache directory context with a given `path` pub fn new(path: &Path) -> KeyDirectory { KeyDirectory { - cache: HashMap::new(), + cache: RwLock::new(HashMap::new()), path: path.to_str().expect("Initialized key directory with empty path").to_owned(), - cache_usage: VecDeque::new(), + cache_usage: RwLock::new(VecDeque::new()), } } @@ -448,25 +484,37 @@ impl KeyDirectory { let json_bytes = json_text.into_bytes(); try!(file.write(&json_bytes)); } + let mut cache = self.cache.write().unwrap(); let id = key_file.id.clone(); - self.cache.insert(id.clone(), key_file); + cache.insert(id.clone(), key_file); Ok(id.clone()) } /// Returns key given by id if corresponding file exists and no load error occured. /// Warns if any error occured during the key loading - pub fn get(&mut self, id: &Uuid) -> Option<&KeyFileContent> { + pub fn get(&self, id: &Uuid) -> Option { let path = self.key_path(id); - self.cache_usage.push_back(id.clone()); - Some(self.cache.entry(id.to_owned()).or_insert( + { + let mut usage = self.cache_usage.write().unwrap(); + usage.push_back(id.clone()); + } + + if !self.cache.read().unwrap().contains_key(id) { match KeyDirectory::load_key(&path) { - Ok(loaded_key) => loaded_key, + Ok(loaded_key) => { + self.cache.write().unwrap().insert(id.to_owned(), loaded_key); + } Err(error) => { warn!(target: "sstore", "error loading key {:?}: {:?}", id, error); return None; } } - )) + } + + // todo: replace with Ref::map when it stabilized to avoid copies + Some(self.cache.read().unwrap().get(id) + .expect("Key should be there, we have just inserted or checked it.") + .clone()) } /// Returns current path to the directory with keys @@ -476,29 +524,65 @@ impl KeyDirectory { /// Removes keys that never been requested during last `MAX_USAGE_TRACK` times pub fn collect_garbage(&mut self) { - let total_usages = self.cache_usage.len(); + let mut cache_usage = self.cache_usage.write().unwrap(); + + let total_usages = cache_usage.len(); let untracked_usages = max(total_usages as i64 - MAX_CACHE_USAGE_TRACK as i64, 0) as usize; if untracked_usages > 0 { - self.cache_usage.drain(..untracked_usages); + cache_usage.drain(..untracked_usages); } - if self.cache.len() <= MAX_CACHE_USAGE_TRACK { return; } + if self.cache.read().unwrap().len() <= MAX_CACHE_USAGE_TRACK { return; } - let uniqs: HashSet<&Uuid> = self.cache_usage.iter().collect(); - let mut removes = HashSet::new(); + let uniqs: HashSet<&Uuid> = cache_usage.iter().collect(); + let removes:Vec = { + let cache = self.cache.read().unwrap(); + cache.keys().cloned().filter(|key| !uniqs.contains(key)).collect() + }; + if removes.is_empty() { return; } + let mut cache = self.cache.write().unwrap(); + for key in removes { cache.remove(&key); } - for key in self.cache.keys() { - if !uniqs.contains(key) { - removes.insert(key.clone()); - } - } - - for removed_key in removes { self.cache.remove(&removed_key); } + cache.shrink_to_fit(); } /// Reports how many keys are currently cached. pub fn cache_size(&self) -> usize { - self.cache.len() + self.cache.read().unwrap().len() + } + + /// Removes key file from key directory + pub fn delete(&mut self, id: &Uuid) -> Result<(), ::std::io::Error> { + let path = self.key_path(id); + + if !self.cache.read().unwrap().contains_key(id) { + return match fs::remove_file(&path) { + Ok(_) => { + self.cache.write().unwrap().remove(&id); + Ok(()) + }, + Err(e) => Err(e) + }; + } + Ok(()) + } + + /// Enumerates all keys in the directory + pub fn list(&self) -> Result, ::std::io::Error> { + let mut result = Vec::new(); + for entry in try!(fs::read_dir(&self.path)) { + let entry = try!(entry); + if !try!(fs::metadata(entry.path())).is_dir() { + match entry.file_name().to_str() { + Some(ref name) => { + if let Ok(uuid) = uuid_from_string(name) { result.push(uuid); } + }, + None => { continue; } + }; + + } + } + Ok(result) } fn key_path(&self, id: &Uuid) -> PathBuf { @@ -536,6 +620,8 @@ impl KeyDirectory { Err(_) => Err(KeyFileLoadError::ParseError(KeyFileParseError::InvalidJson)) } } + + } @@ -590,7 +676,7 @@ mod file_tests { } #[test] - fn can_read_scrypt_krf() { + fn can_read_scrypt_kdf() { let json = Json::from_str( r#" { @@ -626,6 +712,47 @@ mod file_tests { } } + #[test] + fn can_read_scrypt_kdf_params() { + let json = Json::from_str( + r#" + { + "crypto" : { + "cipher" : "aes-128-ctr", + "cipherparams" : { + "iv" : "83dbcc02d8ccb40e466191a123791e0e" + }, + "ciphertext" : "d172bf743a674da9cdad04534d56926ef8358534d458fffccd4e6ad2fbde479c", + "kdf" : "scrypt", + "kdfparams" : { + "dklen" : 32, + "n" : 262144, + "r" : 1, + "p" : 8, + "salt" : "ab0c7876052600dd703518d6fc3fe8984592145b591fc8fb5c6d43190334ba19" + }, + "mac" : "2103ac29920d71da29f15d75b4a16dbe95cfd7ff8faea1056c33131d846e3097" + }, + "id" : "3198bc9c-6672-5ab3-d995-4942343ae5b6", + "version" : 3 + } + "#).unwrap(); + + match KeyFileContent::from_json(&json) { + Ok(key_file) => { + match key_file.crypto.kdf { + KeyFileKdf::Scrypt(scrypt_params) => { + assert_eq!(262144, scrypt_params.n); + assert_eq!(1, scrypt_params.r); + assert_eq!(8, scrypt_params.p); + }, + _ => { panic!("expected kdf params of crypto to be of scrypt type" ); } + } + }, + Err(e) => panic!("Error parsing valid file: {:?}", e) + } + } + #[test] fn can_return_error_no_id() { let json = Json::from_str( @@ -781,7 +908,7 @@ mod file_tests { panic!("Should be error of no identifier, got ok"); }, Err(KeyFileParseError::Crypto(CryptoParseError::Scrypt(_))) => { }, - Err(other_error) => { panic!("should be error of no identifier, got {:?}", other_error); } + Err(other_error) => { panic!("should be scrypt parse error, got {:?}", other_error); } } } @@ -820,14 +947,14 @@ mod file_tests { #[test] fn can_create_key_with_new_id() { let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap(); - let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, U128::zero(), H256::random(), 32, 32)); + let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, H128::zero(), H256::random(), H256::random(), 32, 32)); assert!(!uuid_to_string(&key.id).is_empty()); } #[test] fn can_load_json_from_itself() { let cipher_text: Bytes = FromHex::from_hex("aaaaaaaaaaaaaaaaaaaaaaaaaaa22222222222222222222222").unwrap(); - let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, U128::zero(), H256::random(), 32, 32)); + let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, H128::zero(), H256::random(), H256::random(), 32, 32)); let json = key.to_json(); let loaded_key = KeyFileContent::from_json(&json).unwrap(); @@ -967,7 +1094,7 @@ mod file_tests { mod directory_tests { use super::{KeyDirectory, new_uuid, uuid_to_string, KeyFileContent, KeyFileCrypto, MAX_CACHE_USAGE_TRACK}; use common::*; - use tests::helpers::*; + use devtools::*; #[test] fn key_directory_locates_keys() { @@ -985,7 +1112,7 @@ mod directory_tests { let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap(); let temp_path = RandomTempPath::create_dir(); let mut directory = KeyDirectory::new(&temp_path.as_path()); - let uuid = directory.save(KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, U128::zero(), H256::random(), 32, 32))).unwrap(); + let uuid = directory.save(KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, H128::zero(), H256::random(), H256::random(), 32, 32))).unwrap(); let path = directory.key_path(&uuid); let key = KeyDirectory::load_key(&path).unwrap(); @@ -1001,7 +1128,7 @@ mod directory_tests { let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap(); let mut keys = Vec::new(); for _ in 0..1000 { - let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), U128::zero(), H256::random(), 32, 32)); + let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), H128::zero(), H256::random(), H256::random(), 32, 32)); keys.push(directory.save(key).unwrap()); } @@ -1021,7 +1148,7 @@ mod directory_tests { let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap(); let mut keys = Vec::new(); for _ in 0..1000 { - let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), U128::zero(), H256::random(), 32, 32)); + let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), H128::zero(), H256::random(), H256::random(), 32, 32)); keys.push(directory.save(key).unwrap()); } @@ -1033,13 +1160,21 @@ mod directory_tests { // since all keys are different, should be exactly MAX_CACHE_USAGE_TRACK assert_eq!(MAX_CACHE_USAGE_TRACK, directory.cache_size()) } + + #[test] + fn collects_garbage_on_empty() { + let temp_path = RandomTempPath::create_dir(); + let mut directory = KeyDirectory::new(&temp_path.as_path()); + directory.collect_garbage(); + assert_eq!(0, directory.cache_size()) + } } #[cfg(test)] mod specs { use super::*; use common::*; - use tests::helpers::*; + use devtools::*; #[test] fn can_initiate_key_directory() { @@ -1054,7 +1189,7 @@ mod specs { let temp_path = RandomTempPath::create_dir(); let mut directory = KeyDirectory::new(&temp_path.as_path()); - let uuid = directory.save(KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, U128::zero(), H256::random(), 32, 32))); + let uuid = directory.save(KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, H128::zero(), H256::random(), H256::random(), 32, 32))); assert!(uuid.is_ok()); } @@ -1064,7 +1199,7 @@ mod specs { let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap(); let temp_path = RandomTempPath::create_dir(); let mut directory = KeyDirectory::new(&temp_path.as_path()); - let uuid = directory.save(KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), U128::zero(), H256::random(), 32, 32))).unwrap(); + let uuid = directory.save(KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), H128::zero(), H256::random(), H256::random(), 32, 32))).unwrap(); let key = directory.get(&uuid).unwrap(); @@ -1079,10 +1214,25 @@ mod specs { let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap(); let mut keys = Vec::new(); for _ in 0..10 { - let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), U128::zero(), H256::random(), 32, 32)); + let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), H128::zero(), H256::random(), H256::random(), 32, 32)); keys.push(directory.save(key).unwrap()); } assert_eq!(10, keys.len()) } + + #[test] + fn can_list_keys() { + let temp_path = RandomTempPath::create_dir(); + let mut directory = KeyDirectory::new(&temp_path.as_path()); + + let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap(); + let mut keys = Vec::new(); + for _ in 0..33 { + let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text.clone(), H128::zero(), H256::random(), H256::random(), 32, 32)); + keys.push(directory.save(key).unwrap()); + } + + assert_eq!(33, directory.list().unwrap().len()); + } } diff --git a/util/src/keys/geth_import.rs b/util/src/keys/geth_import.rs new file mode 100644 index 000000000..6c684c37d --- /dev/null +++ b/util/src/keys/geth_import.rs @@ -0,0 +1,176 @@ +// 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 . + +//! Geth keys import/export tool + +use common::*; +use keys::store::SecretStore; +use keys::directory::KeyFileContent; + +/// Enumerates all geth keys in the directory and returns collection of tuples `(accountId, filename)` +pub fn enumerate_geth_keys(path: &Path) -> Result, io::Error> { + let mut entries = Vec::new(); + for entry in try!(fs::read_dir(path)) { + let entry = try!(entry); + if !try!(fs::metadata(entry.path())).is_dir() { + match entry.file_name().to_str() { + Some(name) => { + let parts: Vec<&str> = name.split("--").collect(); + if parts.len() != 3 { continue; } + match Address::from_str(parts[2]) { + Ok(account_id) => { entries.push((account_id, name.to_owned())); } + Err(e) => { panic!("error: {:?}", e); } + } + }, + None => { continue; } + }; + } + } + Ok(entries) +} + +/// Geth import error +#[derive(Debug)] +pub enum ImportError { + /// Io error reading geth file + Io(io::Error), + /// format error + Format, +} + +impl From for ImportError { + fn from (err: io::Error) -> ImportError { + ImportError::Io(err) + } +} + +/// Imports one geth key to the store +pub fn import_geth_key(secret_store: &mut SecretStore, geth_keyfile_path: &Path) -> Result<(), ImportError> { + let mut file = try!(fs::File::open(geth_keyfile_path)); + let mut buf = String::new(); + try!(file.read_to_string(&mut buf)); + + let mut json_result = Json::from_str(&buf); + let mut json = match json_result { + Ok(ref mut parsed_json) => try!(parsed_json.as_object_mut().ok_or(ImportError::Format)), + Err(_) => { return Err(ImportError::Format); } + }; + let crypto_object = try!(json.get("Crypto").and_then(|crypto| crypto.as_object()).ok_or(ImportError::Format)).clone(); + json.insert("crypto".to_owned(), Json::Object(crypto_object)); + json.remove("Crypto"); + match KeyFileContent::load(&Json::Object(json.clone())) { + Ok(key_file) => try!(secret_store.import_key(key_file)), + Err(_) => { return Err(ImportError::Format); } + }; + Ok(()) +} + +/// Imports all geth keys in the directory +pub fn import_geth_keys(secret_store: &mut SecretStore, geth_keyfiles_directory: &Path) -> Result<(), ImportError> { + use std::path::PathBuf; + let geth_files = try!(enumerate_geth_keys(geth_keyfiles_directory)); + for &(ref address, ref file_path) in &geth_files { + let mut path = PathBuf::new(); + path.push(geth_keyfiles_directory); + path.push(file_path); + if let Err(e) = import_geth_key(secret_store, Path::new(&path)) { + warn!("Skipped geth address {}, error importing: {:?}", address, e) + } + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use common::*; + use keys::store::SecretStore; + + fn test_path() -> &'static str { + match ::std::fs::metadata("res") { + Ok(_) => "res/geth_keystore", + Err(_) => "util/res/geth_keystore" + } + } + + fn test_path_param(param_val: &'static str) -> String { + test_path().to_owned() + param_val + } + + #[test] + fn can_enumerate() { + let keys = enumerate_geth_keys(Path::new(test_path())).unwrap(); + assert_eq!(2, keys.len()); + } + + #[test] + fn can_import() { + let temp = ::devtools::RandomTempPath::create_dir(); + let mut secret_store = SecretStore::new_in(temp.as_path()); + import_geth_key(&mut secret_store, Path::new(&test_path_param("/UTC--2016-02-17T09-20-45.721400158Z--3f49624084b67849c7b4e805c5988c21a430f9d9"))).unwrap(); + let key = secret_store.account(&Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap()); + assert!(key.is_some()); + } + + #[test] + fn can_import_directory() { + let temp = ::devtools::RandomTempPath::create_dir(); + let mut secret_store = SecretStore::new_in(temp.as_path()); + import_geth_keys(&mut secret_store, Path::new(test_path())).unwrap(); + + let key = secret_store.account(&Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap()); + assert!(key.is_some()); + + let key = secret_store.account(&Address::from_str("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf").unwrap()); + assert!(key.is_some()); + } + + #[test] + fn imports_as_scrypt_keys() { + use keys::directory::{KeyDirectory, KeyFileKdf}; + let temp = ::devtools::RandomTempPath::create_dir(); + { + let mut secret_store = SecretStore::new_in(temp.as_path()); + import_geth_keys(&mut secret_store, Path::new(test_path())).unwrap(); + } + + let key_directory = KeyDirectory::new(&temp.as_path()); + let key_file = key_directory.get(&H128::from_str("62a0ad73556d496a8e1c0783d30d3ace").unwrap()).unwrap(); + + match key_file.crypto.kdf { + KeyFileKdf::Scrypt(scrypt_params) => { + assert_eq!(262144, scrypt_params.n); + assert_eq!(8, scrypt_params.r); + assert_eq!(1, scrypt_params.p); + }, + _ => { panic!("expected kdf params of crypto to be of scrypt type" ); } + } + } + + #[test] + #[cfg(feature="heavy-tests")] + fn can_decrypt_with_imported() { + use keys::store::EncryptedHashMap; + + let temp = ::devtools::RandomTempPath::create_dir(); + let mut secret_store = SecretStore::new_in(temp.as_path()); + import_geth_keys(&mut secret_store, Path::new(test_path())).unwrap(); + + let val = secret_store.get::(&H128::from_str("62a0ad73556d496a8e1c0783d30d3ace").unwrap(), "123"); + assert!(val.is_ok()); + assert_eq!(32, val.unwrap().len()); + } +} diff --git a/util/src/keys/mod.rs b/util/src/keys/mod.rs index d7ffdb0dd..b9c9dcb08 100644 --- a/util/src/keys/mod.rs +++ b/util/src/keys/mod.rs @@ -17,3 +17,5 @@ //! Key management module pub mod directory; +pub mod store; +mod geth_import; diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs new file mode 100644 index 000000000..78540bdb0 --- /dev/null +++ b/util/src/keys/store.rs @@ -0,0 +1,639 @@ +// 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 . + +//! Secret Store + +use keys::directory::*; +use common::*; +use rcrypto::pbkdf2::*; +use rcrypto::scrypt::*; +use rcrypto::hmac::*; +use crypto; +use chrono::*; + +const KEY_LENGTH: u32 = 32; +const KEY_ITERATIONS: u32 = 10240; +const KEY_LENGTH_AES: u32 = KEY_LENGTH/2; + +const KEY_LENGTH_USIZE: usize = KEY_LENGTH as usize; +const KEY_LENGTH_AES_USIZE: usize = KEY_LENGTH_AES as usize; + +/// Encrypted hash-map, each request should contain password +pub trait EncryptedHashMap { + /// Returns existing value for the key, if any + fn get(&self, key: &Key, password: &str) -> Result; + /// Insert new encrypted key-value and returns previous if there was any + fn insert(&mut self, key: Key, value: Value, password: &str) -> Option; + /// Removes key-value by key and returns the removed one, if any exists and password was provided + fn remove (&mut self, key: &Key, password: Option<&str>) -> Option; + /// Deletes key-value by key and returns if the key-value existed + fn delete(&mut self, key: &Key) -> bool { + self.remove::(key, None).is_some() + } +} + +/// Error retrieving value from encrypted hashmap +#[derive(Debug)] +pub enum EncryptedHashMapError { + /// Encryption failed + InvalidPassword, + /// No key in the hashmap + UnknownIdentifier, + /// Stored value is not well formed for the requested type + InvalidValueFormat(FromBytesError), +} + +/// Error retrieving value from encrypted hashmap +#[derive(Debug)] +pub enum SigningError { + /// Account passed does not exist + NoAccount, + /// Account passed is not unlocked + AccountNotUnlocked, + /// Invalid secret in store + InvalidSecret +} + +/// Represent service for storing encrypted arbitrary data +pub struct SecretStore { + directory: KeyDirectory, + unlocks: RwLock>, +} + +struct AccountUnlock { + secret: H256, + expires: DateTime, +} + +/// Basic account management trait +pub trait AccountProvider : Send + Sync { + /// Lists all accounts + fn accounts(&self) -> Result, ::std::io::Error>; + /// Unlocks account with the password provided + fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError>; + /// Creates account + fn new_account(&self, pass: &str) -> Result; + /// Returns secret for unlocked account + fn account_secret(&self, account: &Address) -> Result; + /// Returns secret for unlocked account + fn sign(&self, account: &Address, message: &H256) -> Result; +} + +/// Thread-safe accounts management +pub struct AccountService { + secret_store: RwLock, +} + +impl AccountProvider for AccountService { + /// Lists all accounts + fn accounts(&self) -> Result, ::std::io::Error> { + Ok(try!(self.secret_store.read().unwrap().accounts()).iter().map(|&(addr, _)| addr).collect::>()) + } + /// Unlocks account with the password provided + fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError> { + self.secret_store.read().unwrap().unlock_account(account, pass) + } + /// Creates account + fn new_account(&self, pass: &str) -> Result { + self.secret_store.write().unwrap().new_account(pass) + } + /// Returns secret for unlocked account + fn account_secret(&self, account: &Address) -> Result { + self.secret_store.read().unwrap().account_secret(account) + } + /// Returns secret for unlocked account + fn sign(&self, account: &Address, message: &H256) -> Result { + self.secret_store.read().unwrap().sign(account, message) + } +} + +impl Default for AccountService { + fn default() -> Self { + AccountService::new() + } +} + +impl AccountService { + /// New account service with the default location + pub fn new() -> Self { + let secret_store = RwLock::new(SecretStore::new()); + secret_store.write().unwrap().try_import_existing(); + AccountService { + secret_store: secret_store + } + } + + #[cfg(test)] + fn new_test(temp: &::devtools::RandomTempPath) -> Self { + let secret_store = RwLock::new(SecretStore::new_test(temp)); + AccountService { + secret_store: secret_store + } + } + + /// Ticks the account service + pub fn tick(&self) { + self.secret_store.write().unwrap().collect_garbage(); + } +} + + +impl Default for SecretStore { + fn default() -> Self { + SecretStore::new() + } +} + +impl SecretStore { + /// new instance of Secret Store in default home directory + pub fn new() -> Self { + let mut path = ::std::env::home_dir().expect("Failed to get home dir"); + path.push(".parity"); + path.push("keys"); + ::std::fs::create_dir_all(&path).expect("Should panic since it is critical to be able to access home dir"); + Self::new_in(&path) + } + + /// new instance of Secret Store in specific directory + pub fn new_in(path: &Path) -> Self { + SecretStore { + directory: KeyDirectory::new(path), + unlocks: RwLock::new(HashMap::new()), + } + } + + /// trys to import keys in the known locations + pub fn try_import_existing(&mut self) { + use std::path::PathBuf; + use keys::geth_import; + + let mut import_path = PathBuf::new(); + import_path.push(::std::env::home_dir().expect("Failed to get home dir")); + import_path.push(".ethereum"); + import_path.push("keystore"); + if let Err(e) = geth_import::import_geth_keys(self, &import_path) { + trace!(target: "sstore", "Geth key not imported: {:?}", e); + } + } + + /// Lists all accounts and corresponding key ids + pub fn accounts(&self) -> Result, ::std::io::Error> { + let accounts = try!(self.directory.list()).iter().map(|key_id| self.directory.get(key_id)) + .filter(|key| key.is_some()) + .map(|key| { let some_key = key.unwrap(); (some_key.account, some_key.id) }) + .filter(|&(ref account, _)| account.is_some()) + .map(|(account, id)| (account.unwrap(), id)) + .collect::>(); + Ok(accounts) + } + + /// Resolves key_id by account address + pub fn account(&self, account: &Address) -> Option { + let mut accounts = match self.accounts() { + Ok(accounts) => accounts, + Err(e) => { warn!(target: "sstore", "Failed to load accounts: {}", e); return None; } + }; + accounts.retain(|&(ref store_account, _)| account == store_account); + accounts.first().and_then(|&(_, ref key_id)| Some(key_id.clone())) + } + + /// Imports pregenerated key, returns error if not saved correctly + pub fn import_key(&mut self, key_file: KeyFileContent) -> Result<(), ::std::io::Error> { + try!(self.directory.save(key_file)); + Ok(()) + } + + #[cfg(test)] + fn new_test(path: &::devtools::RandomTempPath) -> SecretStore { + SecretStore { + directory: KeyDirectory::new(path.as_path()), + unlocks: RwLock::new(HashMap::new()), + } + } + + /// Unlocks account for use + pub fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError> { + let secret_id = try!(self.account(&account).ok_or(EncryptedHashMapError::UnknownIdentifier)); + let secret = try!(self.get(&secret_id, pass)); + { + let mut write_lock = self.unlocks.write().unwrap(); + let mut unlock = write_lock.entry(*account) + .or_insert_with(|| AccountUnlock { secret: secret, expires: UTC::now() }); + unlock.secret = secret; + unlock.expires = UTC::now() + Duration::minutes(20); + } + Ok(()) + } + + /// Creates new account + pub fn new_account(&mut self, pass: &str) -> Result { + let key_pair = crypto::KeyPair::create().expect("Error creating key-pair. Something wrong with crypto libraries?"); + let address = Address::from(key_pair.public().sha3()); + let key_id = H128::random(); + self.insert(key_id.clone(), key_pair.secret().clone(), pass); + + let mut key_file = self.directory.get(&key_id).expect("the key was just inserted"); + key_file.account = Some(address); + try!(self.directory.save(key_file)); + Ok(address) + } + + /// Signs message with unlocked account + pub fn sign(&self, account: &Address, message: &H256) -> Result { + let read_lock = self.unlocks.read().unwrap(); + let unlock = try!(read_lock.get(account).ok_or(SigningError::AccountNotUnlocked)); + match crypto::KeyPair::from_secret(unlock.secret) { + Ok(pair) => match pair.sign(message) { + Ok(signature) => Ok(signature), + Err(_) => Err(SigningError::InvalidSecret) + }, + Err(_) => Err(SigningError::InvalidSecret) + } + } + + /// Returns secret for unlocked account + pub fn account_secret(&self, account: &Address) -> Result { + let read_lock = self.unlocks.read().unwrap(); + let unlock = try!(read_lock.get(account).ok_or(SigningError::AccountNotUnlocked)); + Ok(unlock.secret as crypto::Secret) + } + + /// Makes account unlocks expire and removes unused key files from memory + pub fn collect_garbage(&mut self) { + let mut garbage_lock = self.unlocks.write().unwrap(); + self.directory.collect_garbage(); + let utc = UTC::now(); + let expired_addresses = garbage_lock.iter() + .filter(|&(_, unlock)| unlock.expires < utc) + .map(|(address, _)| address.clone()).collect::>(); + + for expired in expired_addresses { garbage_lock.remove(&expired); } + + garbage_lock.shrink_to_fit(); + } +} + +fn derive_key_iterations(password: &str, salt: &H256, c: u32) -> (Bytes, Bytes) { + let mut h_mac = Hmac::new(::rcrypto::sha2::Sha256::new(), password.as_bytes()); + let mut derived_key = vec![0u8; KEY_LENGTH_USIZE]; + pbkdf2(&mut h_mac, &salt.as_slice(), c, &mut derived_key); + let derived_right_bits = &derived_key[0..KEY_LENGTH_AES_USIZE]; + let derived_left_bits = &derived_key[KEY_LENGTH_AES_USIZE..KEY_LENGTH_USIZE]; + (derived_right_bits.to_vec(), derived_left_bits.to_vec()) +} + +fn derive_key(password: &str, salt: &H256) -> (Bytes, Bytes) { + derive_key_iterations(password, salt, KEY_ITERATIONS) +} + +fn derive_key_scrypt(password: &str, salt: &H256, n: u32, p: u32, r: u32) -> (Bytes, Bytes) { + let mut derived_key = vec![0u8; KEY_LENGTH_USIZE]; + let scrypt_params = ScryptParams::new(n.trailing_zeros() as u8, r, p); + scrypt(password.as_bytes(), &salt.as_slice(), &scrypt_params, &mut derived_key); + let derived_right_bits = &derived_key[0..KEY_LENGTH_AES_USIZE]; + let derived_left_bits = &derived_key[KEY_LENGTH_AES_USIZE..KEY_LENGTH_USIZE]; + (derived_right_bits.to_vec(), derived_left_bits.to_vec()) +} + +fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Bytes { + let mut mac = vec![0u8; KEY_LENGTH_AES_USIZE + cipher_text.len()]; + mac[0..KEY_LENGTH_AES_USIZE].clone_from_slice(derived_left_bits); + mac[KEY_LENGTH_AES_USIZE..cipher_text.len()+KEY_LENGTH_AES_USIZE].clone_from_slice(cipher_text); + mac +} + +impl EncryptedHashMap for SecretStore { + fn get(&self, key: &H128, password: &str) -> Result { + match self.directory.get(key) { + Some(key_file) => { + let (derived_left_bits, derived_right_bits) = match key_file.crypto.kdf { + KeyFileKdf::Pbkdf2(ref params) => derive_key_iterations(password, ¶ms.salt, params.c), + KeyFileKdf::Scrypt(ref params) => derive_key_scrypt(password, ¶ms.salt, params.n, params.p, params.r) + }; + + if derive_mac(&derived_right_bits, &key_file.crypto.cipher_text) + .sha3() != key_file.crypto.mac { return Err(EncryptedHashMapError::InvalidPassword); } + + let mut val = vec![0u8; key_file.crypto.cipher_text.len()]; + match key_file.crypto.cipher_type { + CryptoCipherType::Aes128Ctr(ref iv) => { + crypto::aes::decrypt(&derived_left_bits, &iv.as_slice(), &key_file.crypto.cipher_text, &mut val); + } + }; + + match Value::from_bytes(&val) { + Ok(value) => Ok(value), + Err(bytes_error) => Err(EncryptedHashMapError::InvalidValueFormat(bytes_error)) + } + }, + None => Err(EncryptedHashMapError::UnknownIdentifier) + } + } + + fn insert(&mut self, key: H128, value: Value, password: &str) -> Option { + let previous = if let Ok(previous_value) = self.get(&key, password) { Some(previous_value) } else { None }; + + // crypto random initiators + let salt = H256::random(); + let iv = H128::random(); + + // two parts of derived key + // DK = [ DK[0..15] DK[16..31] ] = [derived_left_bits, derived_right_bits] + let (derived_left_bits, derived_right_bits) = derive_key(password, &salt); + + let mut cipher_text = vec![0u8; value.as_slice().len()]; + // aes-128-ctr with initial vector of iv + crypto::aes::encrypt(&derived_left_bits, &iv.clone(), &value.as_slice(), &mut cipher_text); + + // KECCAK(DK[16..31] ++ ), where DK[16..31] - derived_right_bits + let mac = derive_mac(&derived_right_bits, &cipher_text.clone()).sha3(); + + let mut key_file = KeyFileContent::new( + KeyFileCrypto::new_pbkdf2( + cipher_text, + iv, + salt, + mac, + KEY_ITERATIONS, + KEY_LENGTH)); + key_file.id = key; + if let Err(io_error) = self.directory.save(key_file) { + warn!("Error saving key file: {:?}", io_error); + } + previous + } + + fn remove(&mut self, key: &H128, password: Option<&str>) -> Option { + let previous = if let Some(pass) = password { + if let Ok(previous_value) = self.get(&key, pass) { Some(previous_value) } else { None } + } + else { None }; + + if let Err(io_error) = self.directory.delete(key) { + warn!("Error saving key file: {:?}", io_error); + } + previous + } + +} + +#[cfg(all(test, feature="heavy-tests"))] +mod vector_tests { + use super::{derive_mac,derive_key_iterations}; + use common::*; + + #[test] + fn mac_vector() { + let password = "testpassword"; + let salt = H256::from_str("ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd").unwrap(); + let cipher_text = FromHex::from_hex("5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46").unwrap(); + let iterations = 262144u32; + + let (derived_left_bits, derived_right_bits) = derive_key_iterations(password, &salt, iterations); + assert_eq!("f06d69cdc7da0faffb1008270bca38f5", derived_left_bits.to_hex()); + assert_eq!("e31891a3a773950e6d0fea48a7188551", derived_right_bits.to_hex()); + + let mac_body = derive_mac(&derived_right_bits, &cipher_text); + assert_eq!("e31891a3a773950e6d0fea48a71885515318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46", mac_body.to_hex()); + + let mac = mac_body.sha3(); + assert_eq!("517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2", format!("{:?}", mac)); + } +} + + +#[cfg(test)] +mod tests { + use super::*; + use devtools::*; + use common::*; + use crypto::KeyPair; + use chrono::*; + + #[test] + fn can_insert() { + let temp = RandomTempPath::create_dir(); + let mut sstore = SecretStore::new_test(&temp); + + let id = H128::random(); + sstore.insert(id.clone(), "Cat".to_owned(), "pass"); + + assert!(sstore.get::(&id, "pass").is_ok()); + } + + #[test] + fn can_get_fail() { + let temp = RandomTempPath::create_dir(); + { + use keys::directory::{KeyFileContent, KeyFileCrypto}; + let mut write_sstore = SecretStore::new_test(&temp); + write_sstore.directory.save( + KeyFileContent::new( + KeyFileCrypto::new_pbkdf2( + FromHex::from_hex("5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46").unwrap(), + H128::from_str("6087dab2f9fdbbfaddc31a909735c1e6").unwrap(), + H256::from_str("ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd").unwrap(), + H256::from_str("517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2").unwrap(), + 262144, + 32))) + .unwrap(); + } + let sstore = SecretStore::new_test(&temp); + if let Ok(_) = sstore.get::(&H128::from_str("3198bc9c66725ab3d9954942343ae5b6").unwrap(), "testpassword") { + panic!("should be error loading key, we requested the wrong key"); + } + } + + fn pregenerate_keys(temp: &RandomTempPath, count: usize) -> Vec { + use keys::directory::{KeyFileContent, KeyFileCrypto}; + let mut write_sstore = SecretStore::new_test(&temp); + let mut result = Vec::new(); + for _ in 0..count { + result.push(write_sstore.directory.save( + KeyFileContent::new( + KeyFileCrypto::new_pbkdf2( + FromHex::from_hex("5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46").unwrap(), + H128::from_str("6087dab2f9fdbbfaddc31a909735c1e6").unwrap(), + H256::from_str("ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd").unwrap(), + H256::from_str("517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2").unwrap(), + 262144, + 32))) + .unwrap()); + } + result + } + + fn pregenerate_accounts(temp: &RandomTempPath, count: usize) -> Vec { + use keys::directory::{KeyFileContent, KeyFileCrypto}; + let mut write_sstore = SecretStore::new_test(&temp); + let mut result = Vec::new(); + for i in 0..count { + let mut key_file = + KeyFileContent::new( + KeyFileCrypto::new_pbkdf2( + FromHex::from_hex("5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46").unwrap(), + H128::from_str("6087dab2f9fdbbfaddc31a909735c1e6").unwrap(), + H256::from_str("ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd").unwrap(), + H256::from_str("517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2").unwrap(), + 262144, + 32)); + key_file.account = Some(x!(i as u64)); + result.push(key_file.id.clone()); + write_sstore.import_key(key_file).unwrap(); + } + result + } + + #[test] + #[cfg(feature="heavy-tests")] + fn can_get() { + let temp = RandomTempPath::create_dir(); + let key_id = { + use keys::directory::{KeyFileContent, KeyFileCrypto}; + let mut write_sstore = SecretStore::new_test(&temp); + write_sstore.directory.save( + KeyFileContent::new( + KeyFileCrypto::new_pbkdf2( + FromHex::from_hex("5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46").unwrap(), + H128::from_str("6087dab2f9fdbbfaddc31a909735c1e6").unwrap(), + H256::from_str("ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd").unwrap(), + H256::from_str("517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2").unwrap(), + 262144, + 32))) + .unwrap() + }; + let sstore = SecretStore::new_test(&temp); + if let Err(e) = sstore.get::(&key_id, "testpassword") { + panic!("got no key: {:?}", e); + } + } + + #[test] + fn can_delete() { + let temp = RandomTempPath::create_dir(); + let keys = pregenerate_keys(&temp, 5); + + let mut sstore = SecretStore::new_test(&temp); + sstore.delete(&keys[2]); + + assert_eq!(4, sstore.directory.list().unwrap().len()) + } + + #[test] + fn can_create_account() { + let temp = RandomTempPath::create_dir(); + let mut sstore = SecretStore::new_test(&temp); + sstore.new_account("123").unwrap(); + assert_eq!(1, sstore.accounts().unwrap().len()); + } + + #[test] + fn can_unlock_account() { + let temp = RandomTempPath::create_dir(); + let mut sstore = SecretStore::new_test(&temp); + let address = sstore.new_account("123").unwrap(); + + let secret = sstore.unlock_account(&address, "123"); + assert!(secret.is_ok()); + } + + #[test] + fn can_sign_data() { + let temp = RandomTempPath::create_dir(); + let address = { + let mut sstore = SecretStore::new_test(&temp); + sstore.new_account("334").unwrap() + }; + let signature = { + let sstore = SecretStore::new_test(&temp); + sstore.unlock_account(&address, "334").unwrap(); + sstore.sign(&address, &H256::random()).unwrap() + }; + + assert!(signature != x!(0)); + } + + #[test] + fn can_import_account() { + use keys::directory::{KeyFileContent, KeyFileCrypto}; + let temp = RandomTempPath::create_dir(); + let mut key_file = + KeyFileContent::new( + KeyFileCrypto::new_pbkdf2( + FromHex::from_hex("5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46").unwrap(), + H128::from_str("6087dab2f9fdbbfaddc31a909735c1e6").unwrap(), + H256::from_str("ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd").unwrap(), + H256::from_str("517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2").unwrap(), + 262144, + 32)); + key_file.account = Some(Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap()); + + let mut sstore = SecretStore::new_test(&temp); + + sstore.import_key(key_file).unwrap(); + + assert_eq!(1, sstore.accounts().unwrap().len()); + assert!(sstore.account(&Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap()).is_some()); + } + + #[test] + fn can_list_accounts() { + let temp = RandomTempPath::create_dir(); + pregenerate_accounts(&temp, 30); + let sstore = SecretStore::new_test(&temp); + let accounts = sstore.accounts().unwrap(); + assert_eq!(30, accounts.len()); + } + + #[test] + fn validate_generated_addresses() { + let temp = RandomTempPath::create_dir(); + let mut sstore = SecretStore::new_test(&temp); + let addr = sstore.new_account("test").unwrap(); + sstore.unlock_account(&addr, "test").unwrap(); + let secret = sstore.account_secret(&addr).unwrap(); + let kp = KeyPair::from_secret(secret).unwrap(); + assert_eq!(Address::from(kp.public().sha3()), addr); + } + + #[test] + fn can_create_service() { + let temp = RandomTempPath::create_dir(); + let svc = AccountService::new_test(&temp); + assert!(svc.accounts().unwrap().is_empty()); + } + + #[test] + fn accounts_expire() { + use std::collections::hash_map::*; + + let temp = RandomTempPath::create_dir(); + let svc = AccountService::new_test(&temp); + let address = svc.new_account("pass").unwrap(); + svc.unlock_account(&address, "pass").unwrap(); + assert!(svc.account_secret(&address).is_ok()); + { + let ss_rw = svc.secret_store.write().unwrap(); + let mut ua_rw = ss_rw.unlocks.write().unwrap(); + let entry = ua_rw.entry(address); + if let Entry::Occupied(mut occupied) = entry { occupied.get_mut().expires = UTC::now() - Duration::minutes(1); } + } + + svc.tick(); + + assert!(svc.account_secret(&address).is_err()); + } +} diff --git a/util/src/kvdb.rs b/util/src/kvdb.rs new file mode 100644 index 000000000..df5c2c448 --- /dev/null +++ b/util/src/kvdb.rs @@ -0,0 +1,212 @@ +// 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 . + +//! Key-Value store abstraction with RocksDB backend. + +use std::default::Default; +use rocksdb::{DB, Writable, WriteBatch, IteratorMode, DBVector, DBIterator, + IndexType, Options, DBCompactionStyle, BlockBasedOptions, Direction}; + +/// Write transaction. Batches a sequence of put/delete operations for efficiency. +pub struct DBTransaction { + batch: WriteBatch, +} + +impl Default for DBTransaction { + fn default() -> Self { + DBTransaction::new() + } +} + +impl DBTransaction { + /// Create new transaction. + pub fn new() -> DBTransaction { + DBTransaction { batch: WriteBatch::new() } + } + + /// Insert a key-value pair in the transaction. Any existing value value will be overwritten upon write. + pub fn put(&self, key: &[u8], value: &[u8]) -> Result<(), String> { + self.batch.put(key, value) + } + + /// Delete value by key. + pub fn delete(&self, key: &[u8]) -> Result<(), String> { + self.batch.delete(key) + } +} + +/// Database configuration +pub struct DatabaseConfig { + /// Optional prefix size in bytes. Allows lookup by partial key. + pub prefix_size: Option +} + +/// Database iterator +pub struct DatabaseIterator<'a> { + iter: DBIterator<'a>, +} + +impl<'a> Iterator for DatabaseIterator<'a> { + type Item = (Box<[u8]>, Box<[u8]>); + + fn next(&mut self) -> Option { + self.iter.next() + } +} + +/// Key-Value database. +pub struct Database { + db: DB, +} + +impl Database { + /// Open database with default settings. + pub fn open_default(path: &str) -> Result { + Database::open(&DatabaseConfig { prefix_size: None }, path) + } + + /// Open database file. Creates if it does not exist. + pub fn open(config: &DatabaseConfig, path: &str) -> Result { + let mut opts = Options::new(); + opts.set_max_open_files(256); + opts.create_if_missing(true); + opts.set_use_fsync(false); + opts.set_compaction_style(DBCompactionStyle::DBUniversalCompaction); + /* + opts.set_bytes_per_sync(8388608); + opts.set_disable_data_sync(false); + opts.set_block_cache_size_mb(1024); + opts.set_table_cache_num_shard_bits(6); + opts.set_max_write_buffer_number(32); + opts.set_write_buffer_size(536870912); + opts.set_target_file_size_base(1073741824); + opts.set_min_write_buffer_number_to_merge(4); + opts.set_level_zero_stop_writes_trigger(2000); + opts.set_level_zero_slowdown_writes_trigger(0); + opts.set_compaction_style(DBUniversalCompaction); + opts.set_max_background_compactions(4); + opts.set_max_background_flushes(4); + opts.set_filter_deletes(false); + opts.set_disable_auto_compactions(false); + */ + + if let Some(size) = config.prefix_size { + let mut block_opts = BlockBasedOptions::new(); + block_opts.set_index_type(IndexType::HashSearch); + opts.set_block_based_table_factory(&block_opts); + opts.set_prefix_extractor_fixed_size(size); + } + let db = try!(DB::open(&opts, path)); + Ok(Database { db: db }) + } + + /// Insert a key-value pair in the transaction. Any existing value value will be overwritten. + pub fn put(&self, key: &[u8], value: &[u8]) -> Result<(), String> { + self.db.put(key, value) + } + + /// Delete value by key. + pub fn delete(&self, key: &[u8]) -> Result<(), String> { + self.db.delete(key) + } + + /// Commit transaction to database. + pub fn write(&self, tr: DBTransaction) -> Result<(), String> { + self.db.write(tr.batch) + } + + /// Get value by key. + pub fn get(&self, key: &[u8]) -> Result, String> { + self.db.get(key) + } + + /// Get value by partial key. Prefix size should match configured prefix size. + pub fn get_by_prefix(&self, prefix: &[u8]) -> Option> { + let mut iter = self.db.iterator(IteratorMode::From(prefix, Direction::forward)); + match iter.next() { + // TODO: use prefix_same_as_start read option (not availabele in C API currently) + Some((k, v)) => if k[0 .. prefix.len()] == prefix[..] { Some(v) } else { None }, + _ => None + } + } + + /// Check if there is anything in the database. + pub fn is_empty(&self) -> bool { + self.db.iterator(IteratorMode::Start).next().is_none() + } + + /// Check if there is anything in the database. + pub fn iter(&self) -> DatabaseIterator { + DatabaseIterator { iter: self.db.iterator(IteratorMode::Start) } + } +} + +#[cfg(test)] +mod tests { + use hash::*; + use super::*; + use devtools::*; + use std::str::FromStr; + use std::ops::Deref; + + fn test_db(config: &DatabaseConfig) { + let path = RandomTempPath::create_dir(); + let db = Database::open(config, path.as_path().to_str().unwrap()).unwrap(); + let key1 = H256::from_str("02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc").unwrap(); + let key2 = H256::from_str("03c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc").unwrap(); + let key3 = H256::from_str("01c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc").unwrap(); + + db.put(&key1, b"cat").unwrap(); + db.put(&key2, b"dog").unwrap(); + + assert_eq!(db.get(&key1).unwrap().unwrap().deref(), b"cat"); + + let contents: Vec<_> = db.iter().collect(); + assert_eq!(contents.len(), 2); + assert_eq!(&*contents[0].0, key1.deref()); + assert_eq!(&*contents[0].1, b"cat"); + assert_eq!(&*contents[1].0, key2.deref()); + assert_eq!(&*contents[1].1, b"dog"); + + db.delete(&key1).unwrap(); + assert!(db.get(&key1).unwrap().is_none()); + db.put(&key1, b"cat").unwrap(); + + let transaction = DBTransaction::new(); + transaction.put(&key3, b"elephant").unwrap(); + transaction.delete(&key1).unwrap(); + db.write(transaction).unwrap(); + assert!(db.get(&key1).unwrap().is_none()); + assert_eq!(db.get(&key3).unwrap().unwrap().deref(), b"elephant"); + + if config.prefix_size.is_some() { + assert_eq!(db.get_by_prefix(&key3).unwrap().deref(), b"elephant"); + assert_eq!(db.get_by_prefix(&key2).unwrap().deref(), b"dog"); + } + } + + #[test] + fn kvdb() { + let path = RandomTempPath::create_dir(); + let smoke = Database::open_default(path.as_path().to_str().unwrap()).unwrap(); + assert!(smoke.is_empty()); + test_db(&DatabaseConfig { prefix_size: None }); + test_db(&DatabaseConfig { prefix_size: Some(1) }); + test_db(&DatabaseConfig { prefix_size: Some(8) }); + test_db(&DatabaseConfig { prefix_size: Some(32) }); + } +} + diff --git a/util/src/lib.rs b/util/src/lib.rs index d4f972800..6abf6485d 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -15,21 +15,20 @@ // along with Parity. If not, see . #![warn(missing_docs)] -#![feature(op_assign_traits)] -#![feature(augmented_assignments)] -#![feature(associated_consts)] -#![feature(plugin)] -#![feature(catch_panic)] +#![cfg_attr(feature="dev", feature(plugin))] +#![cfg_attr(feature="dev", plugin(clippy))] + // Clippy settings -#![plugin(clippy)] // TODO [todr] not really sure -#![allow(needless_range_loop)] +#![cfg_attr(feature="dev", allow(needless_range_loop))] // Shorter than if-else -#![allow(match_bool)] +#![cfg_attr(feature="dev", allow(match_bool))] // We use that to be more explicit about handled cases -#![allow(match_same_arms)] +#![cfg_attr(feature="dev", allow(match_same_arms))] // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. -#![allow(clone_on_copy)] +#![cfg_attr(feature="dev", allow(clone_on_copy))] +// In most cases it expresses function flow better +#![cfg_attr(feature="dev", allow(if_not_else))] //! Ethcore-util library //! @@ -85,7 +84,6 @@ //! cargo build --release //! ``` -extern crate target_info; extern crate slab; extern crate rustc_serialize; extern crate mio; @@ -109,15 +107,20 @@ extern crate serde; #[macro_use] extern crate log as rlog; extern crate igd; +extern crate ethcore_devtools as devtools; +extern crate libc; +extern crate target_info; +extern crate bigint; +extern crate chrono; pub mod standard; #[macro_use] pub mod from_json; #[macro_use] pub mod common; +pub mod numbers; pub mod error; pub mod hash; -pub mod uint; pub mod bytes; pub mod rlp; pub mod misc; @@ -128,8 +131,8 @@ pub mod hashdb; pub mod memorydb; pub mod overlaydb; pub mod journaldb; +pub mod kvdb; mod math; -pub mod chainfilter; pub mod crypto; pub mod triehash; pub mod trie; @@ -142,6 +145,7 @@ pub mod network; pub mod log; pub mod panics; pub mod keys; +pub mod table; pub use common::*; pub use misc::*; @@ -150,9 +154,8 @@ pub use rlp::*; pub use hashdb::*; pub use memorydb::*; pub use overlaydb::*; -pub use journaldb::*; +pub use journaldb::JournalDB; pub use math::*; -pub use chainfilter::*; pub use crypto::*; pub use triehash::*; pub use trie::*; @@ -162,6 +165,61 @@ pub use semantic_version::*; pub use network::*; pub use io::*; pub use log::*; +pub use kvdb::*; #[cfg(test)] -mod tests; +mod tests { + use super::numbers::*; + use std::str::FromStr; + + #[test] + fn u256_multi_muls() { + + let (result, _) = U256([0, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, 0])); + assert_eq!(U256([0, 0, 0, 0]), result); + + let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([1, 0, 0, 0])); + assert_eq!(U256([1, 0, 0, 0]), result); + + let (result, _) = U256([5, 0, 0, 0]).overflowing_mul(U256([5, 0, 0, 0])); + assert_eq!(U256([25, 0, 0, 0]), result); + + let (result, _) = U256([0, 5, 0, 0]).overflowing_mul(U256([0, 5, 0, 0])); + assert_eq!(U256([0, 0, 25, 0]), result); + + let (result, _) = U256([0, 0, 0, 1]).overflowing_mul(U256([1, 0, 0, 0])); + assert_eq!(U256([0, 0, 0, 1]), result); + + let (result, _) = U256([0, 0, 0, 5]).overflowing_mul(U256([2, 0, 0, 0])); + assert_eq!(U256([0, 0, 0, 10]), result); + + let (result, _) = U256([0, 0, 1, 0]).overflowing_mul(U256([0, 5, 0, 0])); + assert_eq!(U256([0, 0, 0, 5]), result); + + let (result, _) = U256([0, 0, 8, 0]).overflowing_mul(U256([0, 0, 7, 0])); + assert_eq!(U256([0, 0, 0, 0]), result); + + let (result, _) = U256([2, 0, 0, 0]).overflowing_mul(U256([0, 5, 0, 0])); + assert_eq!(U256([0, 10, 0, 0]), result); + + let (result, _) = U256([1, 0, 0, 0]).overflowing_mul(U256([0, 0, 0, ::std::u64::MAX])); + assert_eq!(U256([0, 0, 0, ::std::u64::MAX]), result); + + let x1 = U256::from_str("0000000000000000000000000000000000000000000000000000012365124623").unwrap(); + let x2sqr_right = U256::from_str("000000000000000000000000000000000000000000014baeef72e0378e2328c9").unwrap(); + let x1sqr = x1 * x1; + assert_eq!(H256::from(x2sqr_right), H256::from(x1sqr)); + let x1cube = x1sqr * x1; + let x1cube_right = U256::from_str("0000000000000000000000000000000001798acde139361466f712813717897b").unwrap(); + assert_eq!(H256::from(x1cube_right), H256::from(x1cube)); + let x1quad = x1cube * x1; + let x1quad_right = U256::from_str("000000000000000000000001adbdd6bd6ff027485484b97f8a6a4c7129756dd1").unwrap(); + assert_eq!(H256::from(x1quad_right), H256::from(x1quad)); + let x1penta = x1quad * x1; + let x1penta_right = U256::from_str("00000000000001e92875ac24be246e1c57e0507e8c46cc8d233b77f6f4c72993").unwrap(); + assert_eq!(H256::from(x1penta_right), H256::from(x1penta)); + let x1septima = x1penta * x1; + let x1septima_right = U256::from_str("00022cca1da3f6e5722b7d3cc5bbfb486465ebc5a708dd293042f932d7eee119").unwrap(); + assert_eq!(H256::from(x1septima_right), H256::from(x1septima)); + } +} diff --git a/util/src/memorydb.rs b/util/src/memorydb.rs index 680a6e1d0..bada4c4c6 100644 --- a/util/src/memorydb.rs +++ b/util/src/memorydb.rs @@ -21,8 +21,10 @@ use bytes::*; use rlp::*; use sha3::*; use hashdb::*; +use heapsize::*; use std::mem; use std::collections::HashMap; +use std::default::Default; #[derive(Debug,Clone)] /// Reference-counted memory-based HashDB implementation. @@ -31,7 +33,7 @@ use std::collections::HashMap; /// with `kill()`, check for existance with `exists()` and lookup a hash to derive /// the data with `lookup()`. Clear with `clear()` and purge the portions of the data /// that have no references with `purge()`. -/// +/// /// # Example /// ```rust /// extern crate ethcore_util; @@ -68,11 +70,18 @@ use std::collections::HashMap; /// assert!(!m.exists(&k)); /// } /// ``` +#[derive(PartialEq)] pub struct MemoryDB { data: HashMap, static_null_rlp: (Bytes, i32), } +impl Default for MemoryDB { + fn default() -> Self { + MemoryDB::new() + } +} + impl MemoryDB { /// Create a new instance of the memory DB. pub fn new() -> MemoryDB { @@ -132,7 +141,7 @@ impl MemoryDB { /// Denote than an existing value has the given key. Used when a key gets removed without /// a prior insert and thus has a negative reference with no value. - /// + /// /// May safely be called even if the key's value is known, in which case it will be a no-op. pub fn denote(&self, key: &H256, value: Bytes) -> &(Bytes, i32) { if self.raw(key) == None { @@ -143,6 +152,11 @@ impl MemoryDB { } self.raw(key).unwrap() } + + /// Returns the size of allocated heap memory + pub fn mem_used(&self) -> usize { + self.data.heap_size_of_children() + } } static NULL_RLP_STATIC: [u8; 1] = [0x80; 1]; diff --git a/util/src/misc.rs b/util/src/misc.rs index ae3dbc5bf..159381603 100644 --- a/util/src/misc.rs +++ b/util/src/misc.rs @@ -18,6 +18,11 @@ use std::fs::File; use common::*; +use rlp::{Stream, RlpStream}; +use target_info::Target; + +include!(concat!(env!("OUT_DIR"), "/version.rs")); +include!(concat!(env!("OUT_DIR"), "/rustc_version.rs")); #[derive(Debug,Clone,PartialEq,Eq)] /// Diff type for specifying a change (or not). @@ -62,3 +67,28 @@ pub fn contents(name: &str) -> Result { try!(file.read_to_end(&mut ret)); Ok(ret) } + +/// Get the standard version string for this software. +pub fn version() -> String { + let sha3 = short_sha(); + let sha3_dash = if sha3.is_empty() { "" } else { "-" }; + let commit_date = commit_date().replace("-", ""); + let date_dash = if commit_date.is_empty() { "" } else { "-" }; + let env = Target::env(); + let env_dash = if env.is_empty() { "" } else { "-" }; + format!("Parity/v{}-unstable{}{}{}{}/{}-{}{}{}/rustc{}", env!("CARGO_PKG_VERSION"), sha3_dash, sha3, date_dash, commit_date, Target::arch(), Target::os(), env_dash, env, rustc_version()) +} + +/// Get the standard version data for this software. +pub fn version_data() -> Bytes { + let mut s = RlpStream::new_list(4); + let v = + (u32::from_str(env!("CARGO_PKG_VERSION_MAJOR")).unwrap() << 16) + + (u32::from_str(env!("CARGO_PKG_VERSION_MINOR")).unwrap() << 8) + + u32::from_str(env!("CARGO_PKG_VERSION_PATCH")).unwrap(); + s.append(&v); + s.append(&"Parity"); + s.append(&rustc_version()); + s.append(&&Target::os()[0..2]); + s.out() +} diff --git a/util/src/network/connection.rs b/util/src/network/connection.rs index 746c745c4..a560c1a91 100644 --- a/util/src/network/connection.rs +++ b/util/src/network/connection.rs @@ -16,6 +16,7 @@ use std::sync::Arc; use std::collections::VecDeque; +use std::net::SocketAddr; use mio::{Handler, Token, EventSet, EventLoop, PollOpt, TryRead, TryWrite}; use mio::tcp::*; use hash::*; @@ -159,27 +160,55 @@ impl Connection { } } + /// Get socket token + pub fn token(&self) -> StreamToken { + self.token + } + + /// Replace socket token + pub fn set_token(&mut self, token: StreamToken) { + self.token = token; + } + + /// Get remote peer address + pub fn remote_addr(&self) -> io::Result { + self.socket.peer_addr() + } + + /// Clone this connection. Clears the receiving buffer of the returned connection. + pub fn try_clone(&self) -> io::Result { + Ok(Connection { + token: self.token, + socket: try!(self.socket.try_clone()), + rec_buf: Vec::new(), + rec_size: 0, + send_queue: self.send_queue.clone(), + interest: EventSet::hup() | EventSet::readable(), + stats: self.stats.clone(), + }) + } + /// Register this connection with the IO event loop. pub fn register_socket(&self, reg: Token, event_loop: &mut EventLoop) -> io::Result<()> { - trace!(target: "net", "connection register; token={:?}", reg); - event_loop.register(&self.socket, reg, self.interest, PollOpt::edge() | PollOpt::oneshot()).or_else(|e| { - debug!("Failed to register {:?}, {:?}", reg, e); - Ok(()) - }) + trace!(target: "network", "connection register; token={:?}", reg); + if let Err(e) = event_loop.register(&self.socket, reg, self.interest, PollOpt::edge() | PollOpt::oneshot()) { + trace!(target: "network", "Failed to register {:?}, {:?}", reg, e); + } + Ok(()) } /// Update connection registration. Should be called at the end of the IO handler. pub fn update_socket(&self, reg: Token, event_loop: &mut EventLoop) -> io::Result<()> { - trace!(target: "net", "connection reregister; token={:?}", reg); + trace!(target: "network", "connection reregister; token={:?}", reg); event_loop.reregister( &self.socket, reg, self.interest, PollOpt::edge() | PollOpt::oneshot()).or_else(|e| { - debug!("Failed to reregister {:?}, {:?}", reg, e); + trace!(target: "network", "Failed to reregister {:?}, {:?}", reg, e); Ok(()) }) } /// Delete connection registration. Should be called at the end of the IO handler. pub fn deregister_socket(&self, event_loop: &mut EventLoop) -> io::Result<()> { - trace!(target: "net", "connection deregister; token={:?}", self.token); + trace!(target: "network", "connection deregister; token={:?}", self.token); event_loop.deregister(&self.socket).ok(); // ignore errors here Ok(()) } @@ -232,15 +261,25 @@ pub struct EncryptedConnection { } impl EncryptedConnection { - - /// Get socket token + + /// Get socket token pub fn token(&self) -> StreamToken { self.connection.token } + /// Replace socket token + pub fn set_token(&mut self, token: StreamToken) { + self.connection.set_token(token); + } + + /// Get remote peer address + pub fn remote_addr(&self) -> io::Result { + self.connection.remote_addr() + } + /// Create an encrypted connection out of the handshake. Consumes a handshake object. - pub fn new(mut handshake: Handshake) -> Result { - let shared = try!(crypto::ecdh::agree(handshake.ecdhe.secret(), &handshake.remote_public)); + pub fn new(handshake: &mut Handshake) -> Result { + let shared = try!(crypto::ecdh::agree(handshake.ecdhe.secret(), &handshake.remote_ephemeral)); let mut nonce_material = H512::new(); if handshake.originated { handshake.remote_nonce.copy_to(&mut nonce_material[0..32]); @@ -274,9 +313,8 @@ impl EncryptedConnection { ingress_mac.update(&mac_material); ingress_mac.update(if handshake.originated { &handshake.ack_cipher } else { &handshake.auth_cipher }); - handshake.connection.expect(ENCRYPTED_HEADER_LEN); - Ok(EncryptedConnection { - connection: handshake.connection, + let mut enc = EncryptedConnection { + connection: try!(handshake.connection.try_clone()), encoder: encoder, decoder: decoder, mac_encoder: mac_encoder, @@ -285,7 +323,9 @@ impl EncryptedConnection { read_state: EncryptedConnectionState::Header, protocol_id: 0, payload_len: 0 - }) + }; + enc.connection.expect(ENCRYPTED_HEADER_LEN); + Ok(enc) } /// Send a packet @@ -414,6 +454,12 @@ impl EncryptedConnection { Ok(()) } + /// Register socket with the event lpop. This should be called at the end of the event loop. + pub fn register_socket(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { + try!(self.connection.register_socket(reg, event_loop)); + Ok(()) + } + /// Update connection registration. This should be called at the end of the event loop. pub fn update_socket(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { try!(self.connection.update_socket(reg, event_loop)); @@ -467,8 +513,14 @@ mod tests { buf_size: usize, } + impl Default for TestSocket { + fn default() -> Self { + TestSocket::new() + } + } + impl TestSocket { - fn new() -> TestSocket { + fn new() -> Self { TestSocket { read_buffer: vec![], write_buffer: vec![], @@ -547,8 +599,14 @@ mod tests { type TestConnection = GenericConnection; + impl Default for TestConnection { + fn default() -> Self { + TestConnection::new() + } + } + impl TestConnection { - pub fn new() -> TestConnection { + pub fn new() -> Self { TestConnection { token: 999998888usize, socket: TestSocket::new(), @@ -563,8 +621,14 @@ mod tests { type TestBrokenConnection = GenericConnection; + impl Default for TestBrokenConnection { + fn default() -> Self { + TestBrokenConnection::new() + } + } + impl TestBrokenConnection { - pub fn new() -> TestBrokenConnection { + pub fn new() -> Self { TestBrokenConnection { token: 999998888usize, socket: TestBrokenSocket { error: "test broken socket".to_owned() }, diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index 3e914761d..d755c58e7 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -14,115 +14,188 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -// This module is a work in progress - -#![allow(dead_code)] //TODO: remove this after everything is done - -use std::collections::{HashSet, BTreeMap}; -use std::cell::{RefCell}; -use std::ops::{DerefMut}; +use bytes::Bytes; +use std::net::SocketAddr; +use std::collections::{HashSet, HashMap, BTreeMap, VecDeque}; +use std::mem; +use std::default::Default; use mio::*; use mio::udp::*; +use sha3::*; +use time; use hash::*; -use sha3::Hashable; use crypto::*; -use network::node::*; +use rlp::*; +use network::node_table::*; +use network::error::NetworkError; +use io::StreamToken; -const ADDRESS_BYTES_SIZE: u32 = 32; ///< Size of address type in bytes. -const ADDRESS_BITS: u32 = 8 * ADDRESS_BYTES_SIZE; ///< Denoted by n in [Kademlia]. -const NODE_BINS: u32 = ADDRESS_BITS - 1; ///< Size of m_state (excludes root, which is us). -const DISCOVERY_MAX_STEPS: u16 = 8; ///< Max iterations of discovery. (discover) -const BUCKET_SIZE: u32 = 16; ///< Denoted by k in [Kademlia]. Number of nodes stored in each bucket. -const ALPHA: usize = 3; ///< Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests. +use network::PROTOCOL_VERSION; + +const ADDRESS_BYTES_SIZE: u32 = 32; // Size of address type in bytes. +const ADDRESS_BITS: u32 = 8 * ADDRESS_BYTES_SIZE; // Denoted by n in [Kademlia]. +const NODE_BINS: u32 = ADDRESS_BITS - 1; // Size of m_state (excludes root, which is us). +const DISCOVERY_MAX_STEPS: u16 = 8; // Max iterations of discovery. (discover) +const BUCKET_SIZE: usize = 16; // Denoted by k in [Kademlia]. Number of nodes stored in each bucket. +const ALPHA: usize = 3; // Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests. +const MAX_DATAGRAM_SIZE: usize = 1280; + +const PACKET_PING: u8 = 1; +const PACKET_PONG: u8 = 2; +const PACKET_FIND_NODE: u8 = 3; +const PACKET_NEIGHBOURS: u8 = 4; + +const PING_TIMEOUT_MS: u64 = 300; + +#[derive(Clone, Debug)] +pub struct NodeEntry { + pub id: NodeId, + pub endpoint: NodeEndpoint, +} + +pub struct BucketEntry { + pub address: NodeEntry, + pub timeout: Option, +} struct NodeBucket { - distance: u32, - nodes: Vec + nodes: VecDeque, //sorted by last active +} + +impl Default for NodeBucket { + fn default() -> Self { + NodeBucket::new() + } } impl NodeBucket { - fn new(distance: u32) -> NodeBucket { + fn new() -> Self { NodeBucket { - distance: distance, - nodes: Vec::new() + nodes: VecDeque::new() } } } -struct Discovery { +struct Datagramm { + payload: Bytes, + address: SocketAddr, +} + +pub struct Discovery { id: NodeId, + secret: Secret, + public_endpoint: NodeEndpoint, + udp_socket: UdpSocket, + token: StreamToken, discovery_round: u16, discovery_id: NodeId, discovery_nodes: HashSet, node_buckets: Vec, + send_queue: VecDeque, + check_timestamps: bool, } -struct FindNodePacket; - -impl FindNodePacket { - fn new(_endpoint: &NodeEndpoint, _id: &NodeId) -> FindNodePacket { - FindNodePacket - } - - fn sign(&mut self, _secret: &Secret) { - } - - fn send(& self, _socket: &mut UdpSocket) { - } +pub struct TableUpdates { + pub added: HashMap, + pub removed: HashSet, } impl Discovery { - pub fn new(id: &NodeId) -> Discovery { + pub fn new(key: &KeyPair, listen: SocketAddr, public: NodeEndpoint, token: StreamToken) -> Discovery { + let socket = UdpSocket::bound(&listen).expect("Error binding UDP socket"); Discovery { - id: id.clone(), + id: key.public().clone(), + secret: key.secret().clone(), + public_endpoint: public, + token: token, discovery_round: 0, discovery_id: NodeId::new(), discovery_nodes: HashSet::new(), - node_buckets: (0..NODE_BINS).map(NodeBucket::new).collect(), + node_buckets: (0..NODE_BINS).map(|_| NodeBucket::new()).collect(), + udp_socket: socket, + send_queue: VecDeque::new(), + check_timestamps: true, } } - pub fn add_node(&mut self, id: &NodeId) { - self.node_buckets[Discovery::distance(&self.id, &id) as usize].nodes.push(id.clone()); + /// Add a new node to discovery table. Pings the node. + pub fn add_node(&mut self, e: NodeEntry) { + let endpoint = e.endpoint.clone(); + self.update_node(e); + self.ping(&endpoint); } - fn start_node_discovery(&mut self, event_loop: &mut EventLoop) { + /// Add a list of known nodes to the table. + pub fn init_node_list(&mut self, mut nodes: Vec) { + for n in nodes.drain(..) { + self.update_node(n); + } + } + + fn update_node(&mut self, e: NodeEntry) { + trace!(target: "discovery", "Inserting {:?}", &e); + let ping = { + let mut bucket = self.node_buckets.get_mut(Discovery::distance(&self.id, &e.id) as usize).unwrap(); + let updated = if let Some(node) = bucket.nodes.iter_mut().find(|n| n.address.id == e.id) { + node.address = e.clone(); + node.timeout = None; + true + } else { false }; + + if !updated { + bucket.nodes.push_front(BucketEntry { address: e, timeout: None }); + } + + if bucket.nodes.len() > BUCKET_SIZE { + //ping least active node + bucket.nodes.back_mut().unwrap().timeout = Some(time::precise_time_ns()); + Some(bucket.nodes.back().unwrap().address.endpoint.clone()) + } else { None } + }; + if let Some(endpoint) = ping { + self.ping(&endpoint); + } + } + + fn clear_ping(&mut self, id: &NodeId) { + let mut bucket = self.node_buckets.get_mut(Discovery::distance(&self.id, &id) as usize).unwrap(); + if let Some(node) = bucket.nodes.iter_mut().find(|n| &n.address.id == id) { + node.timeout = None; + } + } + + fn start(&mut self) { + trace!(target: "discovery", "Starting discovery"); self.discovery_round = 0; - self.discovery_id.randomize(); + self.discovery_id.randomize(); //TODO: use cryptographic nonce self.discovery_nodes.clear(); - self.discover(event_loop); } - fn discover(&mut self, event_loop: &mut EventLoop) { - if self.discovery_round == DISCOVERY_MAX_STEPS - { - debug!("Restarting discovery"); - self.start_node_discovery(event_loop); + fn discover(&mut self) { + if self.discovery_round == DISCOVERY_MAX_STEPS { return; } + trace!(target: "discovery", "Starting round {:?}", self.discovery_round); let mut tried_count = 0; { - let nearest = Discovery::nearest_node_entries(&self.id, &self.discovery_id, &self.node_buckets).into_iter(); - let nodes = RefCell::new(&mut self.discovery_nodes); - let nearest = nearest.filter(|x| nodes.borrow().contains(&x)).take(ALPHA); + let nearest = Discovery::nearest_node_entries(&self.discovery_id, &self.node_buckets).into_iter(); + let nearest = nearest.filter(|x| !self.discovery_nodes.contains(&x.id)).take(ALPHA).collect::>(); for r in nearest { - //let mut p = FindNodePacket::new(&r.endpoint, &self.discovery_id); - //p.sign(&self.secret); - //p.send(&mut self.udp_socket); - let mut borrowed = nodes.borrow_mut(); - borrowed.deref_mut().insert(r.clone()); + let rlp = encode(&(&[self.discovery_id.clone()][..])); + self.send_packet(PACKET_FIND_NODE, &r.endpoint.udp_address(), &rlp); + self.discovery_nodes.insert(r.id.clone()); tried_count += 1; + trace!(target: "discovery", "Sent FindNode to {:?}", &r.endpoint); } } - if tried_count == 0 - { - debug!("Restarting discovery"); - self.start_node_discovery(event_loop); + if tried_count == 0 { + trace!(target: "discovery", "Completing discovery"); + self.discovery_round = DISCOVERY_MAX_STEPS; + self.discovery_nodes.clear(); return; } self.discovery_round += 1; - //event_loop.timeout_ms(Token(NODETABLE_DISCOVERY), 1200).unwrap(); } fn distance(a: &NodeId, b: &NodeId) -> u32 { @@ -138,86 +211,437 @@ impl Discovery { ret } - #[allow(cyclomatic_complexity)] - fn nearest_node_entries<'b>(source: &NodeId, target: &NodeId, buckets: &'b [NodeBucket]) -> Vec<&'b NodeId> - { - // send ALPHA FindNode packets to nodes we know, closest to target - const LAST_BIN: u32 = NODE_BINS - 1; - let mut head = Discovery::distance(source, target); - let mut tail = if head == 0 { LAST_BIN } else { (head - 1) % NODE_BINS }; + fn ping(&mut self, node: &NodeEndpoint) { + let mut rlp = RlpStream::new_list(3); + rlp.append(&PROTOCOL_VERSION); + self.public_endpoint.to_rlp_list(&mut rlp); + node.to_rlp_list(&mut rlp); + trace!(target: "discovery", "Sent Ping to {:?}", &node); + self.send_packet(PACKET_PING, &node.udp_address(), &rlp.drain()); + } - let mut found: BTreeMap> = BTreeMap::new(); + fn send_packet(&mut self, packet_id: u8, address: &SocketAddr, payload: &[u8]) { + let mut rlp = RlpStream::new(); + rlp.append_raw(&[packet_id], 1); + let source = Rlp::new(payload); + rlp.begin_list(source.item_count() + 1); + for i in 0 .. source.item_count() { + rlp.append_raw(source.at(i).as_raw(), 1); + } + let timestamp = time::get_time().sec as u32 + 60; + rlp.append(×tamp); + + let bytes = rlp.drain(); + let hash = bytes.as_ref().sha3(); + let signature = match ec::sign(&self.secret, &hash) { + Ok(s) => s, + Err(_) => { + warn!("Error signing UDP packet"); + return; + } + }; + let mut packet = Bytes::with_capacity(bytes.len() + 32 + 65); + packet.extend(hash.iter()); + packet.extend(signature.iter()); + packet.extend(bytes.iter()); + let signed_hash = (&packet[32..]).sha3(); + packet[0..32].clone_from_slice(&signed_hash); + self.send_to(packet, address.clone()); + } + + #[cfg_attr(feature="dev", allow(map_clone))] + fn nearest_node_entries(target: &NodeId, buckets: &[NodeBucket]) -> Vec { + let mut found: BTreeMap> = BTreeMap::new(); let mut count = 0; - // if d is 0, then we roll look forward, if last, we reverse, else, spread from d - if head > 1 && tail != LAST_BIN { - while head != tail && head < NODE_BINS && count < BUCKET_SIZE - { - for n in &buckets[head as usize].nodes - { - if count < BUCKET_SIZE { - count += 1; - found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n); - } - else { - break; - } - } - if count < BUCKET_SIZE && tail != 0 { - for n in &buckets[tail as usize].nodes { - if count < BUCKET_SIZE { - count += 1; - found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n); - } - else { - break; - } + // Sort nodes by distance to target + for bucket in buckets { + for node in &bucket.nodes { + let distance = Discovery::distance(target, &node.address.id); + found.entry(distance).or_insert_with(Vec::new).push(&node.address); + if count == BUCKET_SIZE { + // delete the most distant element + let remove = { + let (_, last) = found.iter_mut().next_back().unwrap(); + last.pop(); + last.is_empty() + }; + if remove { + found.remove(&distance); } } - - head += 1; - if tail > 0 { - tail -= 1; + else { + count += 1; } } } - else if head < 2 { - while head < NODE_BINS && count < BUCKET_SIZE { - for n in &buckets[head as usize].nodes { - if count < BUCKET_SIZE { - count += 1; - found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n); - } - else { - break; - } - } - head += 1; - } - } - else { - while tail > 0 && count < BUCKET_SIZE { - for n in &buckets[tail as usize].nodes { - if count < BUCKET_SIZE { - count += 1; - found.entry(Discovery::distance(target, &n)).or_insert_with(Vec::new).push(n); - } - else { - break; - } - } - tail -= 1; - } - } - let mut ret:Vec<&NodeId> = Vec::new(); + let mut ret:Vec = Vec::new(); for nodes in found.values() { - for n in nodes { - if ret.len() < BUCKET_SIZE as usize /* && n->endpoint && n->endpoint.isAllowed() */ { - ret.push(n); - } - } + ret.extend(nodes.iter().map(|&n| n.clone())); } ret } + + pub fn writable(&mut self) { + while !self.send_queue.is_empty() { + let data = self.send_queue.pop_front().unwrap(); + match self.udp_socket.send_to(&data.payload, &data.address) { + Ok(Some(size)) if size == data.payload.len() => { + }, + Ok(Some(_)) => { + warn!("UDP sent incomplete datagramm"); + }, + Ok(None) => { + self.send_queue.push_front(data); + return; + } + Err(e) => { + debug!("UDP send error: {:?}, address: {:?}", e, &data.address); + return; + } + } + } + } + + fn send_to(&mut self, payload: Bytes, address: SocketAddr) { + self.send_queue.push_back(Datagramm { payload: payload, address: address }); + } + + pub fn readable(&mut self) -> Option { + let mut buf: [u8; MAX_DATAGRAM_SIZE] = unsafe { mem::uninitialized() }; + match self.udp_socket.recv_from(&mut buf) { + Ok(Some((len, address))) => self.on_packet(&buf[0..len], address).unwrap_or_else(|e| { + debug!("Error processing UDP packet: {:?}", e); + None + }), + Ok(_) => None, + Err(e) => { + debug!("Error reading UPD socket: {:?}", e); + None + } + } + } + + fn on_packet(&mut self, packet: &[u8], from: SocketAddr) -> Result, NetworkError> { + // validate packet + if packet.len() < 32 + 65 + 4 + 1 { + return Err(NetworkError::BadProtocol); + } + + let hash_signed = (&packet[32..]).sha3(); + if hash_signed[..] != packet[0..32] { + return Err(NetworkError::BadProtocol); + } + + let signed = &packet[(32 + 65)..]; + let signature = Signature::from_slice(&packet[32..(32 + 65)]); + let node_id = try!(ec::recover(&signature, &signed.sha3())); + + let packet_id = signed[0]; + let rlp = UntrustedRlp::new(&signed[1..]); + match packet_id { + PACKET_PING => self.on_ping(&rlp, &node_id, &from), + PACKET_PONG => self.on_pong(&rlp, &node_id, &from), + PACKET_FIND_NODE => self.on_find_node(&rlp, &node_id, &from), + PACKET_NEIGHBOURS => self.on_neighbours(&rlp, &node_id, &from), + _ => { + debug!("Unknown UDP packet: {}", packet_id); + Ok(None) + } + } + } + + fn check_timestamp(&self, timestamp: u64) -> Result<(), NetworkError> { + if self.check_timestamps && timestamp < time::get_time().sec as u64{ + debug!(target: "discovery", "Expired packet"); + return Err(NetworkError::Expired); + } + Ok(()) + } + + fn on_ping(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result, NetworkError> { + trace!(target: "discovery", "Got Ping from {:?}", &from); + let source = try!(NodeEndpoint::from_rlp(&try!(rlp.at(1)))); + let dest = try!(NodeEndpoint::from_rlp(&try!(rlp.at(2)))); + let timestamp: u64 = try!(rlp.val_at(3)); + try!(self.check_timestamp(timestamp)); + let mut added_map = HashMap::new(); + let entry = NodeEntry { id: node.clone(), endpoint: source.clone() }; + if !entry.endpoint.is_valid() || !entry.endpoint.is_global() { + debug!(target: "discovery", "Got bad address: {:?}", entry); + } + else { + self.update_node(entry.clone()); + added_map.insert(node.clone(), entry); + } + let hash = rlp.as_raw().sha3(); + let mut response = RlpStream::new_list(2); + dest.to_rlp_list(&mut response); + response.append(&hash); + self.send_packet(PACKET_PONG, from, &response.drain()); + + Ok(Some(TableUpdates { added: added_map, removed: HashSet::new() })) + } + + fn on_pong(&mut self, rlp: &UntrustedRlp, node: &NodeId, from: &SocketAddr) -> Result, NetworkError> { + trace!(target: "discovery", "Got Pong from {:?}", &from); + // TODO: validate pong packet + let dest = try!(NodeEndpoint::from_rlp(&try!(rlp.at(0)))); + let timestamp: u64 = try!(rlp.val_at(2)); + try!(self.check_timestamp(timestamp)); + let mut entry = NodeEntry { id: node.clone(), endpoint: dest }; + if !entry.endpoint.is_valid() { + debug!(target: "discovery", "Bad address: {:?}", entry); + entry.endpoint.address = from.clone(); + } + self.clear_ping(node); + let mut added_map = HashMap::new(); + added_map.insert(node.clone(), entry); + Ok(None) + } + + fn on_find_node(&mut self, rlp: &UntrustedRlp, _node: &NodeId, from: &SocketAddr) -> Result, NetworkError> { + trace!(target: "discovery", "Got FindNode from {:?}", &from); + let target: NodeId = try!(rlp.val_at(0)); + let timestamp: u64 = try!(rlp.val_at(1)); + try!(self.check_timestamp(timestamp)); + let nearest = Discovery::nearest_node_entries(&target, &self.node_buckets); + if nearest.is_empty() { + return Ok(None); + } + let mut packets = Discovery::prepare_neighbours_packets(&nearest); + for p in packets.drain(..) { + self.send_packet(PACKET_NEIGHBOURS, &from, &p); + } + trace!(target: "discovery", "Sent {} Neighbours to {:?}", nearest.len(), &from); + Ok(None) + } + + fn prepare_neighbours_packets(nearest: &[NodeEntry]) -> Vec { + let limit = (MAX_DATAGRAM_SIZE - 109) / 90; + let chunks = nearest.chunks(limit); + let packets = chunks.map(|c| { + let mut rlp = RlpStream::new_list(1); + rlp.begin_list(c.len()); + for n in 0 .. c.len() { + rlp.begin_list(4); + c[n].endpoint.to_rlp(&mut rlp); + rlp.append(&c[n].id); + } + rlp.out() + }); + packets.collect() + } + + fn on_neighbours(&mut self, rlp: &UntrustedRlp, _node: &NodeId, from: &SocketAddr) -> Result, NetworkError> { + // TODO: validate packet + let mut added = HashMap::new(); + trace!(target: "discovery", "Got {} Neighbours from {:?}", try!(rlp.at(0)).item_count(), &from); + for r in try!(rlp.at(0)).iter() { + let endpoint = try!(NodeEndpoint::from_rlp(&r)); + if !endpoint.is_valid() { + debug!(target: "discovery", "Bad address: {:?}", endpoint); + continue; + } + let node_id: NodeId = try!(r.val_at(3)); + if node_id == self.id { + continue; + } + let entry = NodeEntry { id: node_id.clone(), endpoint: endpoint }; + added.insert(node_id, entry.clone()); + self.ping(&entry.endpoint); + self.update_node(entry); + } + Ok(Some(TableUpdates { added: added, removed: HashSet::new() })) + } + + fn check_expired(&mut self, force: bool) -> HashSet { + let now = time::precise_time_ns(); + let mut removed: HashSet = HashSet::new(); + for bucket in &mut self.node_buckets { + bucket.nodes.retain(|node| { + if let Some(timeout) = node.timeout { + if !force && now - timeout < PING_TIMEOUT_MS * 1000_0000 { + true + } + else { + trace!(target: "discovery", "Removed expired node {:?}", &node.address); + removed.insert(node.address.id.clone()); + false + } + } else { true } + }); + } + removed + } + + pub fn round(&mut self) -> Option { + let removed = self.check_expired(false); + self.discover(); + if !removed.is_empty() { + Some(TableUpdates { added: HashMap::new(), removed: removed }) + } else { None } + } + + pub fn refresh(&mut self) { + self.start(); + } + + pub fn register_socket(&self, event_loop: &mut EventLoop) -> Result<(), NetworkError> { + event_loop.register(&self.udp_socket, Token(self.token), EventSet::all(), PollOpt::edge()).expect("Error registering UDP socket"); + Ok(()) + } + + pub fn update_registration(&self, event_loop: &mut EventLoop) -> Result<(), NetworkError> { + let mut registration = EventSet::readable(); + if !self.send_queue.is_empty() { + registration = registration | EventSet::writable(); + } + event_loop.reregister(&self.udp_socket, Token(self.token), registration, PollOpt::edge()).expect("Error reregistering UDP socket"); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use hash::*; + use std::net::*; + use network::node_table::*; + use crypto::KeyPair; + use std::str::FromStr; + use rustc_serialize::hex::FromHex; + use rlp::*; + + #[test] + fn find_node() { + let mut nearest = Vec::new(); + let node = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7770").unwrap(); + for _ in 0..1000 { + nearest.push( NodeEntry { id: node.id.clone(), endpoint: node.endpoint.clone() }); + } + + let packets = Discovery::prepare_neighbours_packets(&nearest); + assert_eq!(packets.len(), 77); + for p in &packets[0..76] { + assert!(p.len() > 1280/2); + assert!(p.len() <= 1280); + } + assert!(packets.last().unwrap().len() > 0); + } + + #[test] + fn discovery() { + let key1 = KeyPair::create().unwrap(); + let key2 = KeyPair::create().unwrap(); + let ep1 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40444").unwrap(), udp_port: 40444 }; + let ep2 = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40445").unwrap(), udp_port: 40445 }; + let mut discovery1 = Discovery::new(&key1, ep1.address.clone(), ep1.clone(), 0); + let mut discovery2 = Discovery::new(&key2, ep2.address.clone(), ep2.clone(), 0); + + let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7770").unwrap(); + let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@127.0.0.1:7771").unwrap(); + discovery1.add_node(NodeEntry { id: node1.id.clone(), endpoint: node1.endpoint.clone() }); + discovery1.add_node(NodeEntry { id: node2.id.clone(), endpoint: node2.endpoint.clone() }); + + discovery2.add_node(NodeEntry { id: key1.public().clone(), endpoint: ep1.clone() }); + discovery2.refresh(); + + for _ in 0 .. 10 { + while !discovery1.send_queue.is_empty() { + let datagramm = discovery1.send_queue.pop_front().unwrap(); + if datagramm.address == ep2.address { + discovery2.on_packet(&datagramm.payload, ep1.address.clone()).ok(); + } + } + while !discovery2.send_queue.is_empty() { + let datagramm = discovery2.send_queue.pop_front().unwrap(); + if datagramm.address == ep1.address { + discovery1.on_packet(&datagramm.payload, ep2.address.clone()).ok(); + } + } + discovery2.round(); + } + assert_eq!(Discovery::nearest_node_entries(&NodeId::new(), &discovery2.node_buckets).len(), 3) + } + + #[test] + fn removes_expired() { + let key = KeyPair::create().unwrap(); + let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40446").unwrap(), udp_port: 40447 }; + let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0); + for _ in 0..1200 { + discovery.add_node(NodeEntry { id: NodeId::random(), endpoint: ep.clone() }); + } + assert!(Discovery::nearest_node_entries(&NodeId::new(), &discovery.node_buckets).len() <= 16); + let removed = discovery.check_expired(true).len(); + assert!(removed > 0); + } + + #[test] + fn packets() { + let key = KeyPair::create().unwrap(); + let ep = NodeEndpoint { address: SocketAddr::from_str("127.0.0.1:40447").unwrap(), udp_port: 40447 }; + let mut discovery = Discovery::new(&key, ep.address.clone(), ep.clone(), 0); + discovery.check_timestamps = false; + let from = SocketAddr::from_str("99.99.99.99:40445").unwrap(); + + let packet = "\ + e9614ccfd9fc3e74360018522d30e1419a143407ffcce748de3e22116b7e8dc92ff74788c0b6663a\ + aa3d67d641936511c8f8d6ad8698b820a7cf9e1be7155e9a241f556658c55428ec0563514365799a\ + 4be2be5a685a80971ddcfa80cb422cdd0101ec04cb847f000001820cfa8215a8d790000000000000\ + 000000000000000000018208ae820d058443b9a3550102\ + ".from_hex().unwrap(); + assert!(discovery.on_packet(&packet, from.clone()).is_ok()); + + let packet = "\ + 577be4349c4dd26768081f58de4c6f375a7a22f3f7adda654d1428637412c3d7fe917cadc56d4e5e\ + 7ffae1dbe3efffb9849feb71b262de37977e7c7a44e677295680e9e38ab26bee2fcbae207fba3ff3\ + d74069a50b902a82c9903ed37cc993c50001f83e82022bd79020010db83c4d001500000000abcdef\ + 12820cfa8215a8d79020010db885a308d313198a2e037073488208ae82823a8443b9a355c5010203\ + 040531b9019afde696e582a78fa8d95ea13ce3297d4afb8ba6433e4154caa5ac6431af1b80ba7602\ + 3fa4090c408f6b4bc3701562c031041d4702971d102c9ab7fa5eed4cd6bab8f7af956f7d565ee191\ + 7084a95398b6a21eac920fe3dd1345ec0a7ef39367ee69ddf092cbfe5b93e5e568ebc491983c09c7\ + 6d922dc3\ + ".from_hex().unwrap(); + assert!(discovery.on_packet(&packet, from.clone()).is_ok()); + + let packet = "\ + 09b2428d83348d27cdf7064ad9024f526cebc19e4958f0fdad87c15eb598dd61d08423e0bf66b206\ + 9869e1724125f820d851c136684082774f870e614d95a2855d000f05d1648b2d5945470bc187c2d2\ + 216fbe870f43ed0909009882e176a46b0102f846d79020010db885a308d313198a2e037073488208\ + ae82823aa0fbc914b16819237dcd8801d7e53f69e9719adecb3cc0e790c57e91ca4461c9548443b9\ + a355c6010203c2040506a0c969a58f6f9095004c0177a6b47f451530cab38966a25cca5cb58f0555 + 42124e\ + ".from_hex().unwrap(); + assert!(discovery.on_packet(&packet, from.clone()).is_ok()); + + let packet = "\ + c7c44041b9f7c7e41934417ebac9a8e1a4c6298f74553f2fcfdcae6ed6fe53163eb3d2b52e39fe91\ + 831b8a927bf4fc222c3902202027e5e9eb812195f95d20061ef5cd31d502e47ecb61183f74a504fe\ + 04c51e73df81f25c4d506b26db4517490103f84eb840ca634cae0d49acb401d8a4c6b6fe8c55b70d\ + 115bf400769cc1400f3258cd31387574077f301b421bc84df7266c44e9e6d569fc56be0081290476\ + 7bf5ccd1fc7f8443b9a35582999983999999280dc62cc8255c73471e0a61da0c89acdc0e035e260a\ + dd7fc0c04ad9ebf3919644c91cb247affc82b69bd2ca235c71eab8e49737c937a2c396\ + ".from_hex().unwrap(); + assert!(discovery.on_packet(&packet, from.clone()).is_ok()); + + let packet = "\ + c679fc8fe0b8b12f06577f2e802d34f6fa257e6137a995f6f4cbfc9ee50ed3710faf6e66f932c4c8\ + d81d64343f429651328758b47d3dbc02c4042f0fff6946a50f4a49037a72bb550f3a7872363a83e1\ + b9ee6469856c24eb4ef80b7535bcf99c0004f9015bf90150f84d846321163782115c82115db84031\ + 55e1427f85f10a5c9a7755877748041af1bcd8d474ec065eb33df57a97babf54bfd2103575fa8291\ + 15d224c523596b401065a97f74010610fce76382c0bf32f84984010203040101b840312c55512422\ + cf9b8a4097e9a6ad79402e87a15ae909a4bfefa22398f03d20951933beea1e4dfa6f968212385e82\ + 9f04c2d314fc2d4e255e0d3bc08792b069dbf8599020010db83c4d001500000000abcdef12820d05\ + 820d05b84038643200b172dcfef857492156971f0e6aa2c538d8b74010f8e140811d53b98c765dd2\ + d96126051913f44582e8c199ad7c6d6819e9a56483f637feaac9448aacf8599020010db885a308d3\ + 13198a2e037073488203e78203e8b8408dcab8618c3253b558d459da53bd8fa68935a719aff8b811\ + 197101a4b2b47dd2d47295286fc00cc081bb542d760717d1bdd6bec2c37cd72eca367d6dd3b9df73\ + 8443b9a355010203b525a138aa34383fec3d2719a0\ + ".from_hex().unwrap(); + assert!(discovery.on_packet(&packet, from.clone()).is_ok()); + } + } diff --git a/util/src/network/error.rs b/util/src/network/error.rs index 4d7fb483e..31e1d785b 100644 --- a/util/src/network/error.rs +++ b/util/src/network/error.rs @@ -15,23 +15,45 @@ // along with Parity. If not, see . use io::IoError; +use crypto::CryptoError; use rlp::*; -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum DisconnectReason { DisconnectRequested, - _TCPError, - _BadProtocol, + TCPError, + BadProtocol, UselessPeer, - _TooManyPeers, - _DuplicatePeer, - _IncompatibleProtocol, - _NullIdentity, - _ClientQuit, - _UnexpectedIdentity, - _LocalIdentity, + TooManyPeers, + DuplicatePeer, + IncompatibleProtocol, + NullIdentity, + ClientQuit, + UnexpectedIdentity, + LocalIdentity, PingTimeout, + Unknown, +} + +impl DisconnectReason { + pub fn from_u8(n: u8) -> DisconnectReason { + match n { + 0 => DisconnectReason::DisconnectRequested, + 1 => DisconnectReason::TCPError, + 2 => DisconnectReason::BadProtocol, + 3 => DisconnectReason::UselessPeer, + 4 => DisconnectReason::TooManyPeers, + 5 => DisconnectReason::DuplicatePeer, + 6 => DisconnectReason::IncompatibleProtocol, + 7 => DisconnectReason::NullIdentity, + 8 => DisconnectReason::ClientQuit, + 9 => DisconnectReason::UnexpectedIdentity, + 10 => DisconnectReason::LocalIdentity, + 11 => DisconnectReason::PingTimeout, + _ => DisconnectReason::Unknown, + } + } } #[derive(Debug)] @@ -41,6 +63,8 @@ pub enum NetworkError { Auth, /// Unrecognised protocol. BadProtocol, + /// Message expired. + Expired, /// Peer not found. PeerNotFound, /// Peer is diconnected. @@ -61,3 +85,28 @@ impl From for NetworkError { } } +impl From for NetworkError { + fn from(_err: CryptoError) -> NetworkError { + NetworkError::Auth + } +} + +#[test] +fn test_errors() { + assert_eq!(DisconnectReason::ClientQuit, DisconnectReason::from_u8(8)); + let mut r = DisconnectReason::DisconnectRequested; + for i in 0 .. 20 { + r = DisconnectReason::from_u8(i); + } + assert_eq!(DisconnectReason::Unknown, r); + + match >::from(DecoderError::RlpIsTooBig) { + NetworkError::Auth => {}, + _ => panic!("Unexpeceted error"), + } + + match >::from(CryptoError::InvalidSecret) { + NetworkError::Auth => {}, + _ => panic!("Unexpeceted error"), + } +} diff --git a/util/src/network/handshake.rs b/util/src/network/handshake.rs index 4b23c4e16..a72cc28ad 100644 --- a/util/src/network/handshake.rs +++ b/util/src/network/handshake.rs @@ -15,16 +15,18 @@ // along with Parity. If not, see . use std::sync::Arc; +use rand::random; use mio::*; use mio::tcp::*; use hash::*; +use rlp::*; use sha3::Hashable; use bytes::Bytes; use crypto::*; use crypto; use network::connection::{Connection}; use network::host::{HostInfo}; -use network::node::NodeId; +use network::node_table::NodeId; use error::*; use network::error::NetworkError; use network::stats::NetworkStats; @@ -36,8 +38,12 @@ enum HandshakeState { New, /// Waiting for auth packet ReadingAuth, + /// Waiting for extended auth packet + ReadingAuthEip8, /// Waiting for ack packet ReadingAck, + /// Waiting for extended ack packet + ReadingAckEip8, /// Ready to start a session StartSession, } @@ -57,18 +63,25 @@ pub struct Handshake { /// Connection nonce pub nonce: H256, /// Handshake public key - pub remote_public: Public, + pub remote_ephemeral: Public, /// Remote connection nonce. pub remote_nonce: H256, + /// Remote RLPx protocol version. + pub remote_version: u64, /// A copy of received encryped auth packet pub auth_cipher: Bytes, /// A copy of received encryped ack packet - pub ack_cipher: Bytes + pub ack_cipher: Bytes, + /// This Handshake is marked for deleteion flag + pub expired: bool, } -const AUTH_PACKET_SIZE: usize = 307; -const ACK_PACKET_SIZE: usize = 210; -const HANDSHAKE_TIMEOUT: u64 = 30000; +const V4_AUTH_PACKET_SIZE: usize = 307; +const V4_ACK_PACKET_SIZE: usize = 210; +const HANDSHAKE_TIMEOUT: u64 = 5000; +const PROTOCOL_VERSION: u64 = 4; +// Amount of bytes added when encrypting with encryptECIES. +const ECIES_OVERHEAD: usize = 113; impl Handshake { /// Create a new handshake object @@ -80,23 +93,45 @@ impl Handshake { state: HandshakeState::New, ecdhe: try!(KeyPair::create()), nonce: nonce.clone(), - remote_public: Public::new(), + remote_ephemeral: Public::new(), remote_nonce: H256::new(), + remote_version: PROTOCOL_VERSION, auth_cipher: Bytes::new(), ack_cipher: Bytes::new(), + expired: false, }) } + /// Get id of the remote node if known + pub fn id(&self) -> &NodeId { + &self.id + } + + /// Get stream token id + pub fn token(&self) -> StreamToken { + self.connection.token() + } + + /// Mark this handshake as inactive to be deleted lated. + pub fn set_expired(&mut self) { + self.expired = true; + } + + /// Check if this handshake is expired. + pub fn expired(&self) -> bool { + self.expired + } + /// Start a handhsake pub fn start(&mut self, io: &IoContext, host: &HostInfo, originated: bool) -> Result<(), UtilError> where Message: Send + Clone{ self.originated = originated; io.register_timer(self.connection.token, HANDSHAKE_TIMEOUT).ok(); if originated { - try!(self.write_auth(host)); + try!(self.write_auth(host.secret(), host.id())); } else { self.state = HandshakeState::ReadingAuth; - self.connection.expect(AUTH_PACKET_SIZE); + self.connection.expect(V4_AUTH_PACKET_SIZE); }; Ok(()) } @@ -108,47 +143,64 @@ impl Handshake { /// Readable IO handler. Drives the state change. pub fn readable(&mut self, io: &IoContext, host: &HostInfo) -> Result<(), UtilError> where Message: Send + Clone { - io.clear_timer(self.connection.token).unwrap(); - match self.state { - HandshakeState::ReadingAuth => { - if let Some(data) = try!(self.connection.readable()) { - try!(self.read_auth(host, &data)); - try!(self.write_ack()); - }; - }, - HandshakeState::ReadingAck => { - if let Some(data) = try!(self.connection.readable()) { - try!(self.read_ack(host, &data)); - self.state = HandshakeState::StartSession; - }; - }, - HandshakeState::StartSession => {}, - _ => { panic!("Unexpected state"); } - } - if self.state != HandshakeState::StartSession { - try!(io.update_registration(self.connection.token)); + if !self.expired() { + io.clear_timer(self.connection.token).unwrap(); + match self.state { + HandshakeState::New => {} + HandshakeState::ReadingAuth => { + if let Some(data) = try!(self.connection.readable()) { + try!(self.read_auth(host.secret(), &data)); + }; + }, + HandshakeState::ReadingAuthEip8 => { + if let Some(data) = try!(self.connection.readable()) { + try!(self.read_auth_eip8(host.secret(), &data)); + }; + }, + HandshakeState::ReadingAck => { + if let Some(data) = try!(self.connection.readable()) { + try!(self.read_ack(host.secret(), &data)); + }; + }, + HandshakeState::ReadingAckEip8 => { + if let Some(data) = try!(self.connection.readable()) { + try!(self.read_ack_eip8(host.secret(), &data)); + }; + }, + HandshakeState::StartSession => {}, + } + if self.state != HandshakeState::StartSession { + try!(io.update_registration(self.connection.token)); + } } Ok(()) } /// Writabe IO handler. pub fn writable(&mut self, io: &IoContext, _host: &HostInfo) -> Result<(), UtilError> where Message: Send + Clone { - io.clear_timer(self.connection.token).unwrap(); - try!(self.connection.writable()); - if self.state != HandshakeState::StartSession { - io.update_registration(self.connection.token).unwrap(); + if !self.expired() { + io.clear_timer(self.connection.token).unwrap(); + try!(self.connection.writable()); + if self.state != HandshakeState::StartSession { + io.update_registration(self.connection.token).unwrap(); + } } Ok(()) } /// Register the socket with the event loop pub fn register_socket>(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { - try!(self.connection.register_socket(reg, event_loop)); + if !self.expired() { + try!(self.connection.register_socket(reg, event_loop)); + } Ok(()) } + /// Update socket registration with the event loop. pub fn update_socket>(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { - try!(self.connection.update_socket(reg, event_loop)); + if !self.expired() { + try!(self.connection.update_socket(reg, event_loop)); + } Ok(()) } @@ -158,49 +210,106 @@ impl Handshake { Ok(()) } + fn set_auth(&mut self, host_secret: &Secret, sig: &[u8], remote_public: &[u8], remote_nonce: &[u8], remote_version: u64) -> Result<(), UtilError> { + self.id.clone_from_slice(remote_public); + self.remote_nonce.clone_from_slice(remote_nonce); + self.remote_version = remote_version; + let shared = try!(ecdh::agree(host_secret, &self.id)); + let signature = Signature::from_slice(sig); + self.remote_ephemeral = try!(ec::recover(&signature, &(&shared ^ &self.remote_nonce))); + Ok(()) + } + /// Parse, validate and confirm auth message - fn read_auth(&mut self, host: &HostInfo, data: &[u8]) -> Result<(), UtilError> { - trace!(target:"net", "Received handshake auth to {:?}", self.connection.socket.peer_addr()); - if data.len() != AUTH_PACKET_SIZE { + fn read_auth(&mut self, secret: &Secret, data: &[u8]) -> Result<(), UtilError> { + trace!(target:"network", "Received handshake auth from {:?}", self.connection.socket.peer_addr()); + if data.len() != V4_AUTH_PACKET_SIZE { debug!(target:"net", "Wrong auth packet size"); return Err(From::from(NetworkError::BadProtocol)); } self.auth_cipher = data.to_vec(); - let auth = try!(ecies::decrypt(host.secret(), data)); - let (sig, rest) = auth.split_at(65); - let (hepubk, rest) = rest.split_at(32); - let (pubk, rest) = rest.split_at(64); - let (nonce, _) = rest.split_at(32); - self.id.clone_from_slice(pubk); - self.remote_nonce.clone_from_slice(nonce); - let shared = try!(ecdh::agree(host.secret(), &self.id)); - let signature = Signature::from_slice(sig); - let spub = try!(ec::recover(&signature, &(&shared ^ &self.remote_nonce))); - self.remote_public = spub.clone(); - if &spub.sha3()[..] != hepubk { - trace!(target:"net", "Handshake hash mismath with {:?}", self.connection.socket.peer_addr()); - return Err(From::from(NetworkError::Auth)); - }; + match ecies::decrypt(secret, &[], data) { + Ok(auth) => { + let (sig, rest) = auth.split_at(65); + let (_, rest) = rest.split_at(32); + let (pubk, rest) = rest.split_at(64); + let (nonce, _) = rest.split_at(32); + try!(self.set_auth(secret, sig, pubk, nonce, PROTOCOL_VERSION)); + try!(self.write_ack()); + } + Err(_) => { + // Try to interpret as EIP-8 packet + let total = (((data[0] as u16) << 8 | (data[1] as u16)) as usize) + 2; + if total < V4_AUTH_PACKET_SIZE { + debug!(target:"net", "Wrong EIP8 auth packet size"); + return Err(From::from(NetworkError::BadProtocol)); + } + let rest = total - data.len(); + self.state = HandshakeState::ReadingAuthEip8; + self.connection.expect(rest); + } + } + Ok(()) + } + + fn read_auth_eip8(&mut self, secret: &Secret, data: &[u8]) -> Result<(), UtilError> { + trace!(target:"network", "Received EIP8 handshake auth from {:?}", self.connection.socket.peer_addr()); + self.auth_cipher.extend_from_slice(data); + let auth = try!(ecies::decrypt(secret, &self.auth_cipher[0..2], &self.auth_cipher[2..])); + let rlp = UntrustedRlp::new(&auth); + let signature: Signature = try!(rlp.val_at(0)); + let remote_public: Public = try!(rlp.val_at(1)); + let remote_nonce: H256 = try!(rlp.val_at(2)); + let remote_version: u64 = try!(rlp.val_at(3)); + try!(self.set_auth(secret, &signature, &remote_public, &remote_nonce, remote_version)); + try!(self.write_ack_eip8()); Ok(()) } /// Parse and validate ack message - fn read_ack(&mut self, host: &HostInfo, data: &[u8]) -> Result<(), UtilError> { - trace!(target:"net", "Received handshake auth to {:?}", self.connection.socket.peer_addr()); - if data.len() != ACK_PACKET_SIZE { + fn read_ack(&mut self, secret: &Secret, data: &[u8]) -> Result<(), UtilError> { + trace!(target:"network", "Received handshake auth to {:?}", self.connection.socket.peer_addr()); + if data.len() != V4_ACK_PACKET_SIZE { debug!(target:"net", "Wrong ack packet size"); return Err(From::from(NetworkError::BadProtocol)); } self.ack_cipher = data.to_vec(); - let ack = try!(ecies::decrypt(host.secret(), data)); - self.remote_public.clone_from_slice(&ack[0..64]); - self.remote_nonce.clone_from_slice(&ack[64..(64+32)]); + match ecies::decrypt(secret, &[], data) { + Ok(ack) => { + self.remote_ephemeral.clone_from_slice(&ack[0..64]); + self.remote_nonce.clone_from_slice(&ack[64..(64+32)]); + self.state = HandshakeState::StartSession; + } + Err(_) => { + // Try to interpret as EIP-8 packet + let total = (((data[0] as u16) << 8 | (data[1] as u16)) as usize) + 2; + if total < V4_ACK_PACKET_SIZE { + debug!(target:"net", "Wrong EIP8 ack packet size"); + return Err(From::from(NetworkError::BadProtocol)); + } + let rest = total - data.len(); + self.state = HandshakeState::ReadingAckEip8; + self.connection.expect(rest); + } + } + Ok(()) + } + + fn read_ack_eip8(&mut self, secret: &Secret, data: &[u8]) -> Result<(), UtilError> { + trace!(target:"network", "Received EIP8 handshake auth from {:?}", self.connection.socket.peer_addr()); + self.ack_cipher.extend_from_slice(data); + let ack = try!(ecies::decrypt(secret, &self.ack_cipher[0..2], &self.ack_cipher[2..])); + let rlp = UntrustedRlp::new(&ack); + self.remote_ephemeral = try!(rlp.val_at(0)); + self.remote_nonce = try!(rlp.val_at(1)); + self.remote_version = try!(rlp.val_at(2)); + self.state = HandshakeState::StartSession; Ok(()) } /// Sends auth message - fn write_auth(&mut self, host: &HostInfo) -> Result<(), UtilError> { - trace!(target:"net", "Sending handshake auth to {:?}", self.connection.socket.peer_addr()); + fn write_auth(&mut self, secret: &Secret, public: &Public) -> Result<(), UtilError> { + trace!(target:"network", "Sending handshake auth to {:?}", self.connection.socket.peer_addr()); let mut data = [0u8; /*Signature::SIZE*/ 65 + /*H256::SIZE*/ 32 + /*Public::SIZE*/ 64 + /*H256::SIZE*/ 32 + 1]; //TODO: use associated constants let len = data.len(); { @@ -211,23 +320,23 @@ impl Handshake { let (nonce, _) = rest.split_at_mut(32); // E(remote-pubk, S(ecdhe-random, ecdh-shared-secret^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x0) - let shared = try!(crypto::ecdh::agree(host.secret(), &self.id)); + let shared = try!(crypto::ecdh::agree(secret, &self.id)); try!(crypto::ec::sign(self.ecdhe.secret(), &(&shared ^ &self.nonce))).copy_to(sig); self.ecdhe.public().sha3_into(hepubk); - host.id().copy_to(pubk); + public.copy_to(pubk); self.nonce.copy_to(nonce); } - let message = try!(crypto::ecies::encrypt(&self.id, &data)); + let message = try!(crypto::ecies::encrypt(&self.id, &[], &data)); self.auth_cipher = message.clone(); self.connection.send(message); - self.connection.expect(ACK_PACKET_SIZE); + self.connection.expect(V4_ACK_PACKET_SIZE); self.state = HandshakeState::ReadingAck; Ok(()) } /// Sends ack message fn write_ack(&mut self) -> Result<(), UtilError> { - trace!(target:"net", "Sending handshake ack to {:?}", self.connection.socket.peer_addr()); + trace!(target:"network", "Sending handshake ack to {:?}", self.connection.socket.peer_addr()); let mut data = [0u8; 1 + /*Public::SIZE*/ 64 + /*H256::SIZE*/ 32]; //TODO: use associated constants let len = data.len(); { @@ -237,10 +346,222 @@ impl Handshake { self.ecdhe.public().copy_to(epubk); self.nonce.copy_to(nonce); } - let message = try!(crypto::ecies::encrypt(&self.id, &data)); + let message = try!(crypto::ecies::encrypt(&self.id, &[], &data)); self.ack_cipher = message.clone(); self.connection.send(message); self.state = HandshakeState::StartSession; Ok(()) } + + /// Sends EIP8 ack message + fn write_ack_eip8(&mut self) -> Result<(), UtilError> { + trace!(target:"network", "Sending EIP8 handshake ack to {:?}", self.connection.socket.peer_addr()); + let mut rlp = RlpStream::new_list(3); + rlp.append(self.ecdhe.public()); + rlp.append(&self.nonce); + rlp.append(&PROTOCOL_VERSION); + + let pad_array = [0u8; 200]; + let pad = &pad_array[0 .. 100 + random::() % 100]; + rlp.append_raw(pad, 0); + + let encoded = rlp.drain(); + let len = (encoded.len() + ECIES_OVERHEAD) as u16; + let prefix = [ (len >> 8) as u8, (len & 0xff) as u8 ]; + let message = try!(crypto::ecies::encrypt(&self.id, &prefix, &encoded)); + self.ack_cipher.extend_from_slice(&prefix); + self.ack_cipher.extend_from_slice(&message); + self.connection.send(self.ack_cipher.clone()); + self.state = HandshakeState::StartSession; + Ok(()) + } } + +#[cfg(test)] +mod test { + use std::sync::Arc; + use std::str::FromStr; + use rustc_serialize::hex::FromHex; + use super::*; + use crypto::*; + use hash::*; + use std::net::SocketAddr; + use mio::tcp::TcpStream; + use network::stats::NetworkStats; + + fn check_auth(h: &Handshake, version: u64) { + assert_eq!(h.id, Public::from_str("fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877").unwrap()); + assert_eq!(h.remote_nonce, H256::from_str("7e968bba13b6c50e2c4cd7f241cc0d64d1ac25c7f5952df231ac6a2bda8ee5d6").unwrap()); + assert_eq!(h.remote_ephemeral, Public::from_str("654d1044b69c577a44e5f01a1209523adb4026e70c62d1c13a067acabc09d2667a49821a0ad4b634554d330a15a58fe61f8a8e0544b310c6de7b0c8da7528a8d").unwrap()); + assert_eq!(h.remote_version, version); + } + + fn check_ack(h: &Handshake, version: u64) { + assert_eq!(h.remote_nonce, H256::from_str("559aead08264d5795d3909718cdd05abd49572e84fe55590eef31a88a08fdffd").unwrap()); + assert_eq!(h.remote_ephemeral, Public::from_str("b6d82fa3409da933dbf9cb0140c5dde89f4e64aec88d476af648880f4a10e1e49fe35ef3e69e93dd300b4797765a747c6384a6ecf5db9c2690398607a86181e4").unwrap()); + assert_eq!(h.remote_version, version); + } + + fn create_handshake(to: Option<&Public>) -> Handshake { + let addr = SocketAddr::from_str("127.0.0.1:50556").unwrap(); + let socket = TcpStream::connect(&addr).unwrap(); + let nonce = H256::new(); + Handshake::new(0, to, socket, &nonce, Arc::new(NetworkStats::new())).unwrap() + } + + #[test] + fn test_handshake_auth_plain() { + let mut h = create_handshake(None); + let secret = Secret::from_str("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291").unwrap(); + let auth = + "\ + 048ca79ad18e4b0659fab4853fe5bc58eb83992980f4c9cc147d2aa31532efd29a3d3dc6a3d89eaf\ + 913150cfc777ce0ce4af2758bf4810235f6e6ceccfee1acc6b22c005e9e3a49d6448610a58e98744\ + ba3ac0399e82692d67c1f58849050b3024e21a52c9d3b01d871ff5f210817912773e610443a9ef14\ + 2e91cdba0bd77b5fdf0769b05671fc35f83d83e4d3b0b000c6b2a1b1bba89e0fc51bf4e460df3105\ + c444f14be226458940d6061c296350937ffd5e3acaceeaaefd3c6f74be8e23e0f45163cc7ebd7622\ + 0f0128410fd05250273156d548a414444ae2f7dea4dfca2d43c057adb701a715bf59f6fb66b2d1d2\ + 0f2c703f851cbf5ac47396d9ca65b6260bd141ac4d53e2de585a73d1750780db4c9ee4cd4d225173\ + a4592ee77e2bd94d0be3691f3b406f9bba9b591fc63facc016bfa8\ + ".from_hex().unwrap(); + + h.read_auth(&secret, &auth).unwrap(); + assert_eq!(h.state, super::HandshakeState::StartSession); + check_auth(&h, 4); + } + + #[test] + fn test_handshake_auth_eip8() { + let mut h = create_handshake(None); + let secret = Secret::from_str("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291").unwrap(); + let auth = + "\ + 01b304ab7578555167be8154d5cc456f567d5ba302662433674222360f08d5f1534499d3678b513b\ + 0fca474f3a514b18e75683032eb63fccb16c156dc6eb2c0b1593f0d84ac74f6e475f1b8d56116b84\ + 9634a8c458705bf83a626ea0384d4d7341aae591fae42ce6bd5c850bfe0b999a694a49bbbaf3ef6c\ + da61110601d3b4c02ab6c30437257a6e0117792631a4b47c1d52fc0f8f89caadeb7d02770bf999cc\ + 147d2df3b62e1ffb2c9d8c125a3984865356266bca11ce7d3a688663a51d82defaa8aad69da39ab6\ + d5470e81ec5f2a7a47fb865ff7cca21516f9299a07b1bc63ba56c7a1a892112841ca44b6e0034dee\ + 70c9adabc15d76a54f443593fafdc3b27af8059703f88928e199cb122362a4b35f62386da7caad09\ + c001edaeb5f8a06d2b26fb6cb93c52a9fca51853b68193916982358fe1e5369e249875bb8d0d0ec3\ + 6f917bc5e1eafd5896d46bd61ff23f1a863a8a8dcd54c7b109b771c8e61ec9c8908c733c0263440e\ + 2aa067241aaa433f0bb053c7b31a838504b148f570c0ad62837129e547678c5190341e4f1693956c\ + 3bf7678318e2d5b5340c9e488eefea198576344afbdf66db5f51204a6961a63ce072c8926c\ + ".from_hex().unwrap(); + + h.read_auth(&secret, &auth[0..super::V4_AUTH_PACKET_SIZE]).unwrap(); + assert_eq!(h.state, super::HandshakeState::ReadingAuthEip8); + h.read_auth_eip8(&secret, &auth[super::V4_AUTH_PACKET_SIZE..]).unwrap(); + assert_eq!(h.state, super::HandshakeState::StartSession); + check_auth(&h, 4); + } + + #[test] + fn test_handshake_auth_eip8_2() { + let mut h = create_handshake(None); + let secret = Secret::from_str("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291").unwrap(); + let auth = + "\ + 01b8044c6c312173685d1edd268aa95e1d495474c6959bcdd10067ba4c9013df9e40ff45f5bfd6f7\ + 2471f93a91b493f8e00abc4b80f682973de715d77ba3a005a242eb859f9a211d93a347fa64b597bf\ + 280a6b88e26299cf263b01b8dfdb712278464fd1c25840b995e84d367d743f66c0e54a586725b7bb\ + f12acca27170ae3283c1073adda4b6d79f27656993aefccf16e0d0409fe07db2dc398a1b7e8ee93b\ + cd181485fd332f381d6a050fba4c7641a5112ac1b0b61168d20f01b479e19adf7fdbfa0905f63352\ + bfc7e23cf3357657455119d879c78d3cf8c8c06375f3f7d4861aa02a122467e069acaf513025ff19\ + 6641f6d2810ce493f51bee9c966b15c5043505350392b57645385a18c78f14669cc4d960446c1757\ + 1b7c5d725021babbcd786957f3d17089c084907bda22c2b2675b4378b114c601d858802a55345a15\ + 116bc61da4193996187ed70d16730e9ae6b3bb8787ebcaea1871d850997ddc08b4f4ea668fbf3740\ + 7ac044b55be0908ecb94d4ed172ece66fd31bfdadf2b97a8bc690163ee11f5b575a4b44e36e2bfb2\ + f0fce91676fd64c7773bac6a003f481fddd0bae0a1f31aa27504e2a533af4cef3b623f4791b2cca6\ + d490\ + ".from_hex().unwrap(); + + h.read_auth(&secret, &auth[0..super::V4_AUTH_PACKET_SIZE]).unwrap(); + assert_eq!(h.state, super::HandshakeState::ReadingAuthEip8); + h.read_auth_eip8(&secret, &auth[super::V4_AUTH_PACKET_SIZE..]).unwrap(); + assert_eq!(h.state, super::HandshakeState::StartSession); + check_auth(&h, 56); + let ack = h.ack_cipher.clone(); + let total = (((ack[0] as u16) << 8 | (ack[1] as u16)) as usize) + 2; + assert_eq!(ack.len(), total); + } + + #[test] + fn test_handshake_ack_plain() { + let remote = Public::from_str("fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877").unwrap(); + let mut h = create_handshake(Some(&remote)); + let secret = Secret::from_str("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee").unwrap(); + let ack = + "\ + 049f8abcfa9c0dc65b982e98af921bc0ba6e4243169348a236abe9df5f93aa69d99cadddaa387662\ + b0ff2c08e9006d5a11a278b1b3331e5aaabf0a32f01281b6f4ede0e09a2d5f585b26513cb794d963\ + 5a57563921c04a9090b4f14ee42be1a5461049af4ea7a7f49bf4c97a352d39c8d02ee4acc416388c\ + 1c66cec761d2bc1c72da6ba143477f049c9d2dde846c252c111b904f630ac98e51609b3b1f58168d\ + dca6505b7196532e5f85b259a20c45e1979491683fee108e9660edbf38f3add489ae73e3dda2c71b\ + d1497113d5c755e942d1\ + ".from_hex().unwrap(); + + h.read_ack(&secret, &ack).unwrap(); + assert_eq!(h.state, super::HandshakeState::StartSession); + check_ack(&h, 4); + } + + #[test] + fn test_handshake_ack_eip8() { + let remote = Public::from_str("fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877").unwrap(); + let mut h = create_handshake(Some(&remote)); + let secret = Secret::from_str("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee").unwrap(); + let ack = + "\ + 01ea0451958701280a56482929d3b0757da8f7fbe5286784beead59d95089c217c9b917788989470\ + b0e330cc6e4fb383c0340ed85fab836ec9fb8a49672712aeabbdfd1e837c1ff4cace34311cd7f4de\ + 05d59279e3524ab26ef753a0095637ac88f2b499b9914b5f64e143eae548a1066e14cd2f4bd7f814\ + c4652f11b254f8a2d0191e2f5546fae6055694aed14d906df79ad3b407d94692694e259191cde171\ + ad542fc588fa2b7333313d82a9f887332f1dfc36cea03f831cb9a23fea05b33deb999e85489e645f\ + 6aab1872475d488d7bd6c7c120caf28dbfc5d6833888155ed69d34dbdc39c1f299be1057810f34fb\ + e754d021bfca14dc989753d61c413d261934e1a9c67ee060a25eefb54e81a4d14baff922180c395d\ + 3f998d70f46f6b58306f969627ae364497e73fc27f6d17ae45a413d322cb8814276be6ddd13b885b\ + 201b943213656cde498fa0e9ddc8e0b8f8a53824fbd82254f3e2c17e8eaea009c38b4aa0a3f306e8\ + 797db43c25d68e86f262e564086f59a2fc60511c42abfb3057c247a8a8fe4fb3ccbadde17514b7ac\ + 8000cdb6a912778426260c47f38919a91f25f4b5ffb455d6aaaf150f7e5529c100ce62d6d92826a7\ + 1778d809bdf60232ae21ce8a437eca8223f45ac37f6487452ce626f549b3b5fdee26afd2072e4bc7\ + 5833c2464c805246155289f4\ + ".from_hex().unwrap(); + + h.read_ack(&secret, &ack[0..super::V4_ACK_PACKET_SIZE]).unwrap(); + assert_eq!(h.state, super::HandshakeState::ReadingAckEip8); + h.read_ack_eip8(&secret, &ack[super::V4_ACK_PACKET_SIZE..]).unwrap(); + assert_eq!(h.state, super::HandshakeState::StartSession); + check_ack(&h, 4); + } + + #[test] + fn test_handshake_ack_eip8_2() { + let remote = Public::from_str("fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877").unwrap(); + let mut h = create_handshake(Some(&remote)); + let secret = Secret::from_str("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee").unwrap(); + let ack = + "\ + 01f004076e58aae772bb101ab1a8e64e01ee96e64857ce82b1113817c6cdd52c09d26f7b90981cd7\ + ae835aeac72e1573b8a0225dd56d157a010846d888dac7464baf53f2ad4e3d584531fa203658fab0\ + 3a06c9fd5e35737e417bc28c1cbf5e5dfc666de7090f69c3b29754725f84f75382891c561040ea1d\ + dc0d8f381ed1b9d0d4ad2a0ec021421d847820d6fa0ba66eaf58175f1b235e851c7e2124069fbc20\ + 2888ddb3ac4d56bcbd1b9b7eab59e78f2e2d400905050f4a92dec1c4bdf797b3fc9b2f8e84a482f3\ + d800386186712dae00d5c386ec9387a5e9c9a1aca5a573ca91082c7d68421f388e79127a5177d4f8\ + 590237364fd348c9611fa39f78dcdceee3f390f07991b7b47e1daa3ebcb6ccc9607811cb17ce51f1\ + c8c2c5098dbdd28fca547b3f58c01a424ac05f869f49c6a34672ea2cbbc558428aa1fe48bbfd6115\ + 8b1b735a65d99f21e70dbc020bfdface9f724a0d1fb5895db971cc81aa7608baa0920abb0a565c9c\ + 436e2fd13323428296c86385f2384e408a31e104670df0791d93e743a3a5194ee6b076fb6323ca59\ + 3011b7348c16cf58f66b9633906ba54a2ee803187344b394f75dd2e663a57b956cb830dd7a908d4f\ + 39a2336a61ef9fda549180d4ccde21514d117b6c6fd07a9102b5efe710a32af4eeacae2cb3b1dec0\ + 35b9593b48b9d3ca4c13d245d5f04169b0b1\ + ".from_hex().unwrap(); + + h.read_ack(&secret, &ack[0..super::V4_ACK_PACKET_SIZE]).unwrap(); + assert_eq!(h.state, super::HandshakeState::ReadingAckEip8); + h.read_ack_eip8(&secret, &ack[super::V4_ACK_PACKET_SIZE..]).unwrap(); + assert_eq!(h.state, super::HandshakeState::StartSession); + check_ack(&h, 57); + } +} + diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 430850453..d4e6d13ef 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -14,17 +14,21 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::net::{SocketAddr, SocketAddrV4}; +use std::net::{SocketAddr}; use std::collections::{HashMap}; use std::hash::{Hasher}; use std::str::{FromStr}; use std::sync::*; use std::ops::*; +use std::cmp::min; +use std::path::{Path, PathBuf}; +use std::io::{Read, Write}; +use std::default::Default; +use std::fs; use mio::*; use mio::tcp::*; -use mio::udp::*; -use target_info::Target; use hash::*; +use misc::version; use crypto::*; use sha3::Hashable; use rlp::*; @@ -32,28 +36,32 @@ use network::handshake::Handshake; use network::session::{Session, SessionData}; use error::*; use io::*; -use network::NetworkProtocolHandler; -use network::node::*; +use network::{NetworkProtocolHandler, PROTOCOL_VERSION}; +use network::node_table::*; use network::stats::NetworkStats; use network::error::DisconnectReason; -use igd::{PortMappingProtocol,search_gateway}; +use network::discovery::{Discovery, TableUpdates, NodeEntry}; +use network::ip_utils::{map_external_address, select_public_address}; type Slab = ::slab::Slab; const _DEFAULT_PORT: u16 = 30304; - -const MAX_CONNECTIONS: usize = 1024; -const IDEAL_PEERS: u32 = 10; - +const MAX_SESSIONS: usize = 1024; +const MAX_HANDSHAKES: usize = 80; +const MAX_HANDSHAKES_PER_ROUND: usize = 32; const MAINTENANCE_TIMEOUT: u64 = 1000; #[derive(Debug)] /// Network service configuration pub struct NetworkConfiguration { - /// IP address to listen for incoming connections - pub listen_address: SocketAddr, - /// IP address to advertise - pub public_address: SocketAddr, + /// Directory path to store network configuration. None means nothing will be saved + pub config_path: Option, + /// IP address to listen for incoming connections. Listen to all connections by default + pub listen_address: Option, + /// IP address to advertise. Detected automatically if none. + pub public_address: Option, + /// Port for UDP connections, same as TCP by default + pub udp_port: Option, /// Enable NAT configuration pub nat_enabled: bool, /// Enable discovery @@ -64,77 +72,61 @@ pub struct NetworkConfiguration { pub boot_nodes: Vec, /// Use provided node key instead of default pub use_secret: Option, + /// Number of connected peers to maintain + pub ideal_peers: u32, +} + +impl Default for NetworkConfiguration { + fn default() -> Self { + NetworkConfiguration::new() + } } impl NetworkConfiguration { /// Create a new instance of default settings. - pub fn new() -> NetworkConfiguration { + pub fn new() -> Self { NetworkConfiguration { - listen_address: SocketAddr::from_str("0.0.0.0:30304").unwrap(), - public_address: SocketAddr::from_str("0.0.0.0:30304").unwrap(), + config_path: None, + listen_address: None, + public_address: None, + udp_port: None, nat_enabled: true, discovery_enabled: true, pin: false, boot_nodes: Vec::new(), use_secret: None, + ideal_peers: 25, } } /// Create new default configuration with sepcified listen port. pub fn new_with_port(port: u16) -> NetworkConfiguration { let mut config = NetworkConfiguration::new(); - config.listen_address = SocketAddr::from_str(&format!("0.0.0.0:{}", port)).unwrap(); - config.public_address = SocketAddr::from_str(&format!("0.0.0.0:{}", port)).unwrap(); + config.listen_address = Some(SocketAddr::from_str(&format!("0.0.0.0:{}", port)).unwrap()); config } - /// Conduct NAT if needed. - pub fn prepared(self) -> Self { - let mut listen = self.listen_address; - let mut public = self.public_address; - - if self.nat_enabled { - info!("Enabling NAT..."); - match search_gateway() { - Err(ref err) => info!("Error: {}", err), - Ok(gateway) => { - let int_addr = SocketAddrV4::from_str("127.0.0.1:30304").unwrap(); - match gateway.get_any_address(PortMappingProtocol::TCP, int_addr, 0, "Parity Node/TCP") { - Err(ref err) => { - info!("There was an error! {}", err); - }, - Ok(ext_addr) => { - info!("Local gateway: {}, External ip address: {}", gateway, ext_addr); - public = SocketAddr::V4(ext_addr); - listen = SocketAddr::V4(int_addr); - }, - } - }, - } - } - - NetworkConfiguration { - listen_address: listen, - public_address: public, - nat_enabled: false, - discovery_enabled: self.discovery_enabled, - pin: self.pin, - boot_nodes: self.boot_nodes, - use_secret: self.use_secret, - } + /// Create new default configuration for localhost-only connection with random port (usefull for testing) + pub fn new_local() -> NetworkConfiguration { + let mut config = NetworkConfiguration::new(); + config.listen_address = Some(SocketAddr::from_str("127.0.0.1:0").unwrap()); + config.nat_enabled = false; + config } } // Tokens -//const TOKEN_BEGIN: usize = USER_TOKEN_START; // TODO: ICE in rustc 1.7.0-nightly (49c382779 2016-01-12) -const TOKEN_BEGIN: usize = 32; -const TCP_ACCEPT: usize = TOKEN_BEGIN + 1; -const IDLE: usize = TOKEN_BEGIN + 2; -const NODETABLE_RECEIVE: usize = TOKEN_BEGIN + 3; -const NODETABLE_MAINTAIN: usize = TOKEN_BEGIN + 4; -const NODETABLE_DISCOVERY: usize = TOKEN_BEGIN + 5; -const FIRST_CONNECTION: usize = TOKEN_BEGIN + 16; -const LAST_CONNECTION: usize = FIRST_CONNECTION + MAX_CONNECTIONS - 1; +const TCP_ACCEPT: usize = LAST_HANDSHAKE + 1; +const IDLE: usize = LAST_HANDSHAKE + 2; +const DISCOVERY: usize = LAST_HANDSHAKE + 3; +const DISCOVERY_REFRESH: usize = LAST_HANDSHAKE + 4; +const DISCOVERY_ROUND: usize = LAST_HANDSHAKE + 5; +const INIT_PUBLIC: usize = LAST_HANDSHAKE + 6; +const FIRST_SESSION: usize = 0; +const LAST_SESSION: usize = FIRST_SESSION + MAX_SESSIONS - 1; +const FIRST_HANDSHAKE: usize = LAST_SESSION + 1; +const LAST_HANDSHAKE: usize = FIRST_HANDSHAKE + MAX_HANDSHAKES - 1; +const USER_TIMER: usize = LAST_HANDSHAKE + 256; /// Protocol handler level packet id pub type PacketId = u8; @@ -192,49 +184,54 @@ impl Encodable for CapabilityInfo { pub struct NetworkContext<'s, Message> where Message: Send + Sync + Clone + 'static, 's { io: &'s IoContext>, protocol: ProtocolId, - connections: Arc>>, - session: Option, + sessions: Arc>>, + session: Option, + session_id: Option, } impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone + 'static, { /// Create a new network IO access point. Takes references to all the data that can be updated within the IO handler. - fn new(io: &'s IoContext>, - protocol: ProtocolId, - session: Option, connections: Arc>>) -> NetworkContext<'s, Message> { + fn new(io: &'s IoContext>, + protocol: ProtocolId, + session: Option, sessions: Arc>>) -> NetworkContext<'s, Message> { + let id = session.as_ref().map(|s| s.lock().unwrap().token()); NetworkContext { io: io, protocol: protocol, + session_id: id, session: session, - connections: connections, + sessions: sessions, + } + } + + fn resolve_session(&self, peer: PeerId) -> Option { + match self.session_id { + Some(id) if id == peer => self.session.clone(), + _ => self.sessions.read().unwrap().get(peer).cloned(), } } /// Send a packet over the network to another peer. pub fn send(&self, peer: PeerId, packet_id: PacketId, data: Vec) -> Result<(), UtilError> { - if let Some(connection) = self.connections.read().unwrap().get(peer).cloned() { - match *connection.lock().unwrap().deref_mut() { - ConnectionEntry::Session(ref mut s) => { - s.send_packet(self.protocol, packet_id as u8, &data).unwrap_or_else(|e| { - warn!(target: "net", "Send error: {:?}", e); - }); //TODO: don't copy vector data - try!(self.io.update_registration(peer)); - }, - _ => warn!(target: "net", "Send: Peer is not connected yet") - } + let session = self.resolve_session(peer); + if let Some(session) = session { + try!(session.lock().unwrap().deref_mut().send_packet(self.protocol, packet_id as u8, &data)); + try!(self.io.update_registration(peer)); } else { - warn!(target: "net", "Send: Peer does not exist") + trace!(target: "network", "Send: Peer no longer exist") } Ok(()) } - /// Respond to a current network message. Panics if no there is no packet in the context. + /// Respond to a current network message. Panics if no there is no packet in the context. If the session is expired returns nothing. pub fn respond(&self, packet_id: PacketId, data: Vec) -> Result<(), UtilError> { - match self.session { - Some(session) => self.send(session, packet_id, data), - None => { - panic!("Respond: Session does not exist") - } - } + assert!(self.session.is_some(), "Respond called without network context"); + self.send(self.session_id.unwrap(), packet_id, data) + } + + /// Send an IO message + pub fn message(&self, msg: Message) { + self.io.message(NetworkIoMessage::User(msg)); } /// Disable current protocol capability for given peer. If no capabilities left peer gets disconnected. @@ -260,10 +257,9 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone /// Returns peer identification string pub fn peer_info(&self, peer: PeerId) -> String { - if let Some(connection) = self.connections.read().unwrap().get(peer).cloned() { - if let ConnectionEntry::Session(ref s) = *connection.lock().unwrap().deref() { - return s.info.client_version.clone() - } + let session = self.resolve_session(peer); + if let Some(session) = session { + return session.lock().unwrap().info.client_version.clone() } "unknown".to_owned() } @@ -281,10 +277,12 @@ pub struct HostInfo { pub protocol_version: u32, /// Client identifier pub client_version: String, - /// TCP connection port. - pub listen_port: u16, /// Registered capabilities (handlers) - pub capabilities: Vec + pub capabilities: Vec, + /// Local address + discovery port + pub local_endpoint: NodeEndpoint, + /// Public address + discovery port + pub public_endpoint: Option, } impl HostInfo { @@ -305,12 +303,8 @@ impl HostInfo { } } -enum ConnectionEntry { - Handshake(Handshake), - Session(Session) -} - -type SharedConnectionEntry = Arc>; +type SharedSession = Arc>; +type SharedHandshake = Arc>; #[derive(Copy, Clone)] struct ProtocolTimer { @@ -321,58 +315,74 @@ struct ProtocolTimer { /// Root IO handler. Manages protocol handlers, IO timers and network connections. pub struct Host where Message: Send + Sync + Clone { pub info: RwLock, - udp_socket: Mutex, tcp_listener: Mutex, - connections: Arc>>, - nodes: RwLock>, + handshakes: Arc>>, + sessions: Arc>>, + discovery: Mutex>, + nodes: RwLock, handlers: RwLock>>>, timers: RwLock>, timer_counter: RwLock, stats: Arc, + pinned_nodes: Vec, } impl Host where Message: Send + Sync + Clone { /// Create a new instance - pub fn new(config: NetworkConfiguration) -> Host { - let config = config.prepared(); + pub fn new(config: NetworkConfiguration) -> Result, UtilError> { + let mut listen_address = match config.listen_address { + None => SocketAddr::from_str("0.0.0.0:30304").unwrap(), + Some(addr) => addr, + }; - let addr = config.listen_address; + let keys = if let Some(ref secret) = config.use_secret { + KeyPair::from_secret(secret.clone()).unwrap() + } else { + config.config_path.clone().and_then(|ref p| load_key(&Path::new(&p))) + .map_or_else(|| { + let key = KeyPair::create().unwrap(); + if let Some(path) = config.config_path.clone() { + save_key(&Path::new(&path), &key.secret()); + } + key + }, + |s| KeyPair::from_secret(s).expect("Error creating node secret key")) + }; + let path = config.config_path.clone(); // Setup the server socket - let tcp_listener = TcpListener::bind(&addr).unwrap(); - let udp_socket = UdpSocket::bound(&addr).unwrap(); + let tcp_listener = try!(TcpListener::bind(&listen_address)); + listen_address = SocketAddr::new(listen_address.ip(), try!(tcp_listener.local_addr()).port()); + let udp_port = config.udp_port.unwrap_or(listen_address.port()); + let local_endpoint = NodeEndpoint { address: listen_address, udp_port: udp_port }; + let mut host = Host:: { info: RwLock::new(HostInfo { - keys: if let Some(ref secret) = config.use_secret { KeyPair::from_secret(secret.clone()).unwrap() } else { KeyPair::create().unwrap() }, + keys: keys, config: config, nonce: H256::random(), - protocol_version: 4, - client_version: format!("Parity/{}/{}-{}-{}", env!("CARGO_PKG_VERSION"), Target::arch(), Target::env(), Target::os()), - listen_port: 0, + protocol_version: PROTOCOL_VERSION, + client_version: version(), capabilities: Vec::new(), + public_endpoint: None, + local_endpoint: local_endpoint, }), - udp_socket: Mutex::new(udp_socket), + discovery: Mutex::new(None), tcp_listener: Mutex::new(tcp_listener), - connections: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_CONNECTION, MAX_CONNECTIONS))), - nodes: RwLock::new(HashMap::new()), + handshakes: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_HANDSHAKE, MAX_HANDSHAKES))), + sessions: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_SESSION, MAX_SESSIONS))), + nodes: RwLock::new(NodeTable::new(path)), handlers: RwLock::new(HashMap::new()), timers: RwLock::new(HashMap::new()), - timer_counter: RwLock::new(LAST_CONNECTION + 1), + timer_counter: RwLock::new(USER_TIMER), stats: Arc::new(NetworkStats::default()), + pinned_nodes: Vec::new(), }; - let port = host.info.read().unwrap().config.listen_address.port(); - host.info.write().unwrap().deref_mut().listen_port = port; - - /* - match ::ifaces::Interface::get_all().unwrap().into_iter().filter(|x| x.kind == ::ifaces::Kind::Packet && x.addr.is_some()).next() { - Some(iface) => config.public_address = iface.addr.unwrap(), - None => warn!("No public network interface"), - */ let boot_nodes = host.info.read().unwrap().config.boot_nodes.clone(); for n in boot_nodes { host.add_node(&n); } - host + Ok(host) } pub fn stats(&self) -> Arc { @@ -383,7 +393,12 @@ impl Host where Message: Send + Sync + Clone { match Node::from_str(id) { Err(e) => { warn!("Could not add node: {:?}", e); }, Ok(n) => { - self.nodes.write().unwrap().insert(n.id.clone(), n); + let entry = NodeEntry { endpoint: n.endpoint.clone(), id: n.id.clone() }; + self.pinned_nodes.push(n.id.clone()); + self.nodes.write().unwrap().add_node(n); + if let Some(ref mut discovery) = *self.discovery.lock().unwrap().deref_mut() { + discovery.add_node(entry); + } } } } @@ -392,8 +407,65 @@ impl Host where Message: Send + Sync + Clone { self.info.read().unwrap().client_version.clone() } - pub fn client_id(&self) -> NodeId { - self.info.read().unwrap().id().clone() + pub fn external_url(&self) -> Option { + self.info.read().unwrap().public_endpoint.as_ref().map(|e| format!("{}", Node::new(self.info.read().unwrap().id().clone(), e.clone()))) + } + + pub fn local_url(&self) -> String { + let r = format!("{}", Node::new(self.info.read().unwrap().id().clone(), self.info.read().unwrap().local_endpoint.clone())); + println!("{}", r); + r + } + + fn init_public_interface(&self, io: &IoContext>) -> Result<(), UtilError> { + io.clear_timer(INIT_PUBLIC).unwrap(); + if self.info.read().unwrap().public_endpoint.is_some() { + return Ok(()); + } + let local_endpoint = self.info.read().unwrap().local_endpoint.clone(); + let public_address = self.info.read().unwrap().config.public_address.clone(); + let public_endpoint = match public_address { + None => { + let public_address = select_public_address(local_endpoint.address.port()); + let public_endpoint = NodeEndpoint { address: public_address, udp_port: local_endpoint.udp_port }; + if self.info.read().unwrap().config.nat_enabled { + match map_external_address(&local_endpoint) { + Some(endpoint) => { + info!("NAT mapped to external address {}", endpoint.address); + endpoint + }, + None => public_endpoint + } + } else { + public_endpoint + } + } + Some(addr) => NodeEndpoint { address: addr, udp_port: local_endpoint.udp_port } + }; + + self.info.write().unwrap().public_endpoint = Some(public_endpoint.clone()); + info!("Public node URL: {}", self.external_url().unwrap()); + + // Initialize discovery. + let discovery = { + let info = self.info.read().unwrap(); + if info.config.discovery_enabled && !info.config.pin { + Some(Discovery::new(&info.keys, public_endpoint.address.clone(), public_endpoint, DISCOVERY)) + } else { None } + }; + + if let Some(mut discovery) = discovery { + discovery.init_node_list(self.nodes.read().unwrap().unordered_entries()); + for n in self.nodes.read().unwrap().unordered_entries() { + discovery.add_node(n.clone()); + } + *self.discovery.lock().unwrap().deref_mut() = Some(discovery); + io.register_stream(DISCOVERY).expect("Error registering UDP listener"); + io.register_timer(DISCOVERY_REFRESH, 7200).expect("Error registering discovery timer"); + io.register_timer(DISCOVERY_ROUND, 300).expect("Error registering discovery timer"); + } + try!(io.register_stream(TCP_ACCEPT)); + Ok(()) } fn maintain_network(&self, io: &IoContext>) { @@ -402,98 +474,86 @@ impl Host where Message: Send + Sync + Clone { } fn have_session(&self, id: &NodeId) -> bool { - self.connections.read().unwrap().iter().any(|e| match *e.lock().unwrap().deref() { ConnectionEntry::Session(ref s) => s.info.id.eq(&id), _ => false }) + self.sessions.read().unwrap().iter().any(|e| e.lock().unwrap().info.id.eq(&id)) + } + + fn session_count(&self) -> usize { + self.sessions.read().unwrap().count() } fn connecting_to(&self, id: &NodeId) -> bool { - self.connections.read().unwrap().iter().any(|e| match *e.lock().unwrap().deref() { ConnectionEntry::Handshake(ref h) => h.id.eq(&id), _ => false }) + self.handshakes.read().unwrap().iter().any(|e| e.lock().unwrap().id.eq(&id)) + } + + fn handshake_count(&self) -> usize { + self.handshakes.read().unwrap().count() } fn keep_alive(&self, io: &IoContext>) { let mut to_kill = Vec::new(); - for e in self.connections.write().unwrap().iter_mut() { - if let ConnectionEntry::Session(ref mut s) = *e.lock().unwrap().deref_mut() { - if !s.keep_alive(io) { - s.disconnect(DisconnectReason::PingTimeout); - to_kill.push(s.token()); - } + for e in self.sessions.write().unwrap().iter_mut() { + let mut s = e.lock().unwrap(); + if !s.keep_alive(io) { + s.disconnect(DisconnectReason::PingTimeout); + to_kill.push(s.token()); } } for p in to_kill { - self.kill_connection(p, io); + self.kill_connection(p, io, true); } } fn connect_peers(&self, io: &IoContext>) { - struct NodeInfo { - id: NodeId, - peer_type: PeerType + let ideal_peers = { self.info.read().unwrap().deref().config.ideal_peers }; + let pin = { self.info.read().unwrap().deref().config.pin }; + let session_count = self.session_count(); + if session_count >= ideal_peers as usize { + return; } - let mut to_connect: Vec = Vec::new(); - - let mut req_conn = 0; - //TODO: use nodes from discovery here - //for n in self.node_buckets.iter().flat_map(|n| &n.nodes).map(|id| NodeInfo { id: id.clone(), peer_type: self.nodes.get(id).unwrap().peer_type}) { - let pin = self.info.read().unwrap().deref().config.pin; - for n in self.nodes.read().unwrap().values().map(|n| NodeInfo { id: n.id.clone(), peer_type: n.peer_type }) { - let connected = self.have_session(&n.id) || self.connecting_to(&n.id); - let required = n.peer_type == PeerType::Required; - if connected && required { - req_conn += 1; - } - else if !connected && (!pin || required) { - to_connect.push(n); - } + let handshake_count = self.handshake_count(); + // allow 16 slots for incoming connections + let handshake_limit = MAX_HANDSHAKES - 16; + if handshake_count >= handshake_limit { + return; } - for n in &to_connect { - if n.peer_type == PeerType::Required { - if req_conn < IDEAL_PEERS { - self.connect_peer(&n.id, io); - } - req_conn += 1; - } - } - - if !pin { - let pending_count = 0; //TODO: - let peer_count = 0; - let mut open_slots = IDEAL_PEERS - peer_count - pending_count + req_conn; - if open_slots > 0 { - for n in &to_connect { - if n.peer_type == PeerType::Optional && open_slots > 0 { - open_slots -= 1; - self.connect_peer(&n.id, io); - } - } - } + let nodes = if pin { self.pinned_nodes.clone() } else { self.nodes.read().unwrap().nodes() }; + for id in nodes.iter().filter(|ref id| !self.have_session(id) && !self.connecting_to(id)) + .take(min(MAX_HANDSHAKES_PER_ROUND, handshake_limit - handshake_count)) { + self.connect_peer(&id, io); } + debug!(target: "network", "Connecting peers: {} sessions, {} pending", self.session_count(), self.handshake_count()); } - #[allow(single_match)] + #[cfg_attr(feature="dev", allow(single_match))] fn connect_peer(&self, id: &NodeId, io: &IoContext>) { if self.have_session(id) { - warn!("Aborted connect. Node already connected."); + trace!(target: "network", "Aborted connect. Node already connected."); return; } if self.connecting_to(id) { - warn!("Aborted connect. Node already connecting."); + trace!(target: "network", "Aborted connect. Node already connecting."); return; } let socket = { let address = { let mut nodes = self.nodes.write().unwrap(); - let node = nodes.get_mut(id).unwrap(); - node.last_attempted = Some(::time::now()); - node.endpoint.address + if let Some(node) = nodes.get_mut(id) { + node.last_attempted = Some(::time::now()); + node.endpoint.address + } + else { + debug!(target: "network", "Connection to expired node aborted"); + return; + } }; match TcpStream::connect(&address) { Ok(socket) => socket, - Err(_) => { - warn!("Cannot connect to node"); + Err(e) => { + debug!("Can't connect to address {:?}: {:?}", address, e); return; } } @@ -501,23 +561,23 @@ impl Host where Message: Send + Sync + Clone { self.create_connection(socket, Some(id), io); } - #[allow(block_in_if_condition_stmt)] + #[cfg_attr(feature="dev", allow(block_in_if_condition_stmt))] fn create_connection(&self, socket: TcpStream, id: Option<&NodeId>, io: &IoContext>) { let nonce = self.info.write().unwrap().next_nonce(); - let mut connections = self.connections.write().unwrap(); - if connections.insert_with(|token| { + let mut handshakes = self.handshakes.write().unwrap(); + if handshakes.insert_with(|token| { let mut handshake = Handshake::new(token, id, socket, &nonce, self.stats.clone()).expect("Can't create handshake"); handshake.start(io, &self.info.read().unwrap(), id.is_some()).and_then(|_| io.register_stream(token)).unwrap_or_else (|e| { - debug!(target: "net", "Handshake create error: {:?}", e); + debug!(target: "network", "Handshake create error: {:?}", e); }); - Arc::new(Mutex::new(ConnectionEntry::Handshake(handshake))) + Arc::new(Mutex::new(handshake)) }).is_none() { - warn!("Max connections reached"); + debug!(target: "network", "Max handshakes reached"); } } fn accept(&self, io: &IoContext>) { - trace!(target: "net", "accept"); + trace!(target: "network", "Accepting incoming connection"); loop { let socket = match self.tcp_listener.lock().unwrap().accept() { Ok(None) => break, @@ -532,192 +592,280 @@ impl Host where Message: Send + Sync + Clone { io.update_registration(TCP_ACCEPT).expect("Error registering TCP listener"); } - #[allow(single_match)] - fn connection_writable(&self, token: StreamToken, io: &IoContext>) { - let mut create_session = false; - let mut kill = false; - if let Some(connection) = self.connections.read().unwrap().get(token).cloned() { - match *connection.lock().unwrap().deref_mut() { - ConnectionEntry::Handshake(ref mut h) => { - match h.writable(io, &self.info.read().unwrap()) { - Err(e) => { - debug!(target: "net", "Handshake write error: {:?}", e); - kill = true; - }, - Ok(_) => () - } - if h.done() { - create_session = true; - } - }, - ConnectionEntry::Session(ref mut s) => { - match s.writable(io, &self.info.read().unwrap()) { - Err(e) => { - debug!(target: "net", "Session write error: {:?}", e); - kill = true; - }, - Ok(_) => () - } - io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e)); - } + fn handshake_writable(&self, token: StreamToken, io: &IoContext>) { + let handshake = { self.handshakes.read().unwrap().get(token).cloned() }; + if let Some(handshake) = handshake { + let mut h = handshake.lock().unwrap(); + if let Err(e) = h.writable(io, &self.info.read().unwrap()) { + trace!(target: "network", "Handshake write error: {}: {:?}", token, e); } - } - if kill { - self.kill_connection(token, io); //TODO: mark connection as dead an check in kill_connection - return; - } else if create_session { - self.start_session(token, io); - io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e)); + } + } + + fn session_writable(&self, token: StreamToken, io: &IoContext>) { + let session = { self.sessions.read().unwrap().get(token).cloned() }; + if let Some(session) = session { + let mut s = session.lock().unwrap(); + if let Err(e) = s.writable(io, &self.info.read().unwrap()) { + trace!(target: "network", "Session write error: {}: {:?}", token, e); + } + io.update_registration(token).unwrap_or_else(|e| debug!(target: "network", "Session registration error: {:?}", e)); } } fn connection_closed(&self, token: TimerToken, io: &IoContext>) { - self.kill_connection(token, io); + self.kill_connection(token, io, true); } - fn connection_readable(&self, token: StreamToken, io: &IoContext>) { - let mut ready_data: Vec = Vec::new(); - let mut packet_data: Option<(ProtocolId, PacketId, Vec)> = None; + fn handshake_readable(&self, token: StreamToken, io: &IoContext>) { let mut create_session = false; let mut kill = false; - if let Some(connection) = self.connections.read().unwrap().get(token).cloned() { - match *connection.lock().unwrap().deref_mut() { - ConnectionEntry::Handshake(ref mut h) => { - if let Err(e) = h.readable(io, &self.info.read().unwrap()) { - debug!(target: "net", "Handshake read error: {:?}", e); - kill = true; - } - if h.done() { - create_session = true; - } - }, - ConnectionEntry::Session(ref mut s) => { - match s.readable(io, &self.info.read().unwrap()) { - Err(e) => { - debug!(target: "net", "Handshake read error: {:?}", e); - kill = true; - }, - Ok(SessionData::Ready) => { - for (p, _) in self.handlers.read().unwrap().iter() { - if s.have_capability(p) { - ready_data.push(p); - } - } - }, - Ok(SessionData::Packet { - data, - protocol, - packet_id, - }) => { - match self.handlers.read().unwrap().get(protocol) { - None => { warn!(target: "net", "No handler found for protocol: {:?}", protocol) }, - Some(_) => packet_data = Some((protocol, packet_id, data)), - } - }, - Ok(SessionData::None) => {}, - } - } + let handshake = { self.handshakes.read().unwrap().get(token).cloned() }; + if let Some(handshake) = handshake { + let mut h = handshake.lock().unwrap(); + if let Err(e) = h.readable(io, &self.info.read().unwrap()) { + debug!(target: "network", "Handshake read error: {}: {:?}", token, e); + kill = true; } - } + if h.done() { + create_session = true; + } + } if kill { - self.kill_connection(token, io); //TODO: mark connection as dead an check in kill_connection + self.kill_connection(token, io, true); return; } else if create_session { self.start_session(token, io); - io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e)); + return; + } + io.update_registration(token).unwrap_or_else(|e| debug!(target: "network", "Token registration error: {:?}", e)); + } + + fn session_readable(&self, token: StreamToken, io: &IoContext>) { + let mut ready_data: Vec = Vec::new(); + let mut packet_data: Option<(ProtocolId, PacketId, Vec)> = None; + let mut kill = false; + let session = { self.sessions.read().unwrap().get(token).cloned() }; + if let Some(session) = session.clone() { + let mut s = session.lock().unwrap(); + match s.readable(io, &self.info.read().unwrap()) { + Err(e) => { + debug!(target: "network", "Session read error: {}: {:?}", token, e); + kill = true; + }, + Ok(SessionData::Ready) => { + for (p, _) in self.handlers.read().unwrap().iter() { + if s.have_capability(p) { + ready_data.push(p); + } + } + }, + Ok(SessionData::Packet { + data, + protocol, + packet_id, + }) => { + match self.handlers.read().unwrap().get(protocol) { + None => { warn!(target: "network", "No handler found for protocol: {:?}", protocol) }, + Some(_) => packet_data = Some((protocol, packet_id, data)), + } + }, + Ok(SessionData::None) => {}, + } + } + if kill { + self.kill_connection(token, io, true); } for p in ready_data { let h = self.handlers.read().unwrap().get(p).unwrap().clone(); - h.connected(&NetworkContext::new(io, p, Some(token), self.connections.clone()), &token); + h.connected(&NetworkContext::new(io, p, session.clone(), self.sessions.clone()), &token); } if let Some((p, packet_id, data)) = packet_data { let h = self.handlers.read().unwrap().get(p).unwrap().clone(); - h.read(&NetworkContext::new(io, p, Some(token), self.connections.clone()), &token, packet_id, &data[1..]); + h.read(&NetworkContext::new(io, p, session.clone(), self.sessions.clone()), &token, packet_id, &data[1..]); } - io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Token registration error: {:?}", e)); + io.update_registration(token).unwrap_or_else(|e| debug!(target: "network", "Token registration error: {:?}", e)); } fn start_session(&self, token: StreamToken, io: &IoContext>) { - let mut connections = self.connections.write().unwrap(); - if connections.get(token).is_none() { - return; // handshake expired + let mut handshakes = self.handshakes.write().unwrap(); + if handshakes.get(token).is_none() { + return; } - connections.replace_with(token, |c| { - match Arc::try_unwrap(c).ok().unwrap().into_inner().unwrap() { - ConnectionEntry::Handshake(h) => { - let session = Session::new(h, io, &self.info.read().unwrap()).expect("Session creation error"); - io.update_registration(token).expect("Error updating session registration"); - self.stats.inc_sessions(); - Some(Arc::new(Mutex::new(ConnectionEntry::Session(session)))) - }, - _ => { None } // handshake expired + + // turn a handshake into a session + let mut sessions = self.sessions.write().unwrap(); + let mut h = handshakes.get_mut(token).unwrap().lock().unwrap(); + if h.expired { + return; + } + io.deregister_stream(token).expect("Error deleting handshake registration"); + h.set_expired(); + let originated = h.originated; + let mut session = match Session::new(&mut h, &self.info.read().unwrap()) { + Ok(s) => s, + Err(e) => { + debug!(target: "network", "Session creation error: {:?}", e); + return; } - }).ok(); + }; + if !originated { + let session_count = sessions.count(); + let ideal_peers = { self.info.read().unwrap().deref().config.ideal_peers }; + if session_count >= ideal_peers as usize { + session.disconnect(DisconnectReason::TooManyPeers); + return; + } + } + let result = sessions.insert_with(move |session_token| { + session.set_token(session_token); + io.register_stream(session_token).expect("Error creating session registration"); + self.stats.inc_sessions(); + trace!(target: "network", "Creating session {} -> {}", token, session_token); + if !originated { + // Add it no node table + if let Ok(address) = session.remote_addr() { + let entry = NodeEntry { id: session.id().clone(), endpoint: NodeEndpoint { address: address, udp_port: address.port() } }; + self.nodes.write().unwrap().add_node(Node::new(entry.id.clone(), entry.endpoint.clone())); + let mut discovery = self.discovery.lock().unwrap(); + if let Some(ref mut discovery) = *discovery.deref_mut() { + discovery.add_node(entry); + } + } + } + Arc::new(Mutex::new(session)) + }); + if result.is_none() { + warn!("Max sessions reached"); + } } fn connection_timeout(&self, token: StreamToken, io: &IoContext>) { - self.kill_connection(token, io) + self.kill_connection(token, io, true) } - fn kill_connection(&self, token: StreamToken, io: &IoContext>) { + fn kill_connection(&self, token: StreamToken, io: &IoContext>, remote: bool) { let mut to_disconnect: Vec = Vec::new(); - { - let mut connections = self.connections.write().unwrap(); - if let Some(connection) = connections.get(token).cloned() { - match *connection.lock().unwrap().deref_mut() { - ConnectionEntry::Handshake(_) => { - connections.remove(token); - }, - ConnectionEntry::Session(ref mut s) if s.is_ready() => { - for (p, _) in self.handlers.read().unwrap().iter() { - if s.have_capability(p) { - to_disconnect.push(p); + let mut failure_id = None; + let mut deregister = false; + let mut expired_session = None; + match token { + FIRST_HANDSHAKE ... LAST_HANDSHAKE => { + let handshakes = self.handshakes.write().unwrap(); + if let Some(handshake) = handshakes.get(token).cloned() { + let mut handshake = handshake.lock().unwrap(); + if !handshake.expired() { + handshake.set_expired(); + failure_id = Some(handshake.id().clone()); + deregister = true; + } + } + }, + FIRST_SESSION ... LAST_SESSION => { + let sessions = self.sessions.write().unwrap(); + if let Some(session) = sessions.get(token).cloned() { + expired_session = Some(session.clone()); + let mut s = session.lock().unwrap(); + if !s.expired() { + if s.is_ready() { + for (p, _) in self.handlers.read().unwrap().iter() { + if s.have_capability(p) { + to_disconnect.push(p); + } } } - connections.remove(token); - }, - _ => {}, + s.set_expired(); + failure_id = Some(s.id().clone()); + deregister = true; + } } + }, + _ => {}, + } + if let Some(id) = failure_id { + if remote { + self.nodes.write().unwrap().note_failure(&id); } - io.deregister_stream(token).expect("Error deregistering stream"); } for p in to_disconnect { let h = self.handlers.read().unwrap().get(p).unwrap().clone(); - h.disconnected(&NetworkContext::new(io, p, Some(token), self.connections.clone()), &token); + h.disconnected(&NetworkContext::new(io, p, expired_session.clone(), self.sessions.clone()), &token); } + if deregister { + io.deregister_stream(token).expect("Error deregistering stream"); + } + } + + fn update_nodes(&self, io: &IoContext>, node_changes: TableUpdates) { + let mut to_remove: Vec = Vec::new(); + { + { + let handshakes = self.handshakes.write().unwrap(); + for c in handshakes.iter() { + let h = c.lock().unwrap(); + if node_changes.removed.contains(&h.id()) { + to_remove.push(h.token()); + } + } + } + { + let sessions = self.sessions.write().unwrap(); + for c in sessions.iter() { + let s = c.lock().unwrap(); + if node_changes.removed.contains(&s.id()) { + to_remove.push(s.token()); + } + } + } + } + for i in to_remove { + self.kill_connection(i, io, false); + } + self.nodes.write().unwrap().update(node_changes); } } impl IoHandler> for Host where Message: Send + Sync + Clone + 'static { /// Initialize networking fn initialize(&self, io: &IoContext>) { - io.register_stream(TCP_ACCEPT).expect("Error registering TCP listener"); - io.register_stream(NODETABLE_RECEIVE).expect("Error registering UDP listener"); io.register_timer(IDLE, MAINTENANCE_TIMEOUT).expect("Error registering Network idle timer"); - //io.register_timer(NODETABLE_MAINTAIN, 7200); + io.register_timer(INIT_PUBLIC, 0).expect("Error registering initialization timer"); + self.maintain_network(io) } fn stream_hup(&self, io: &IoContext>, stream: StreamToken) { - trace!(target: "net", "Hup: {}", stream); + trace!(target: "network", "Hup: {}", stream); match stream { - FIRST_CONNECTION ... LAST_CONNECTION => self.connection_closed(stream, io), - _ => warn!(target: "net", "Unexpected hup"), + FIRST_SESSION ... LAST_SESSION => self.connection_closed(stream, io), + FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.connection_closed(stream, io), + _ => warn!(target: "network", "Unexpected hup"), }; } fn stream_readable(&self, io: &IoContext>, stream: StreamToken) { match stream { - FIRST_CONNECTION ... LAST_CONNECTION => self.connection_readable(stream, io), - NODETABLE_RECEIVE => {}, - TCP_ACCEPT => self.accept(io), + FIRST_SESSION ... LAST_SESSION => self.session_readable(stream, io), + FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_readable(stream, io), + DISCOVERY => { + let node_changes = { self.discovery.lock().unwrap().as_mut().unwrap().readable() }; + if let Some(node_changes) = node_changes { + self.update_nodes(io, node_changes); + } + io.update_registration(DISCOVERY).expect("Error updating discovery registration"); + }, + TCP_ACCEPT => self.accept(io), _ => panic!("Received unknown readable token"), } } fn stream_writable(&self, io: &IoContext>, stream: StreamToken) { match stream { - FIRST_CONNECTION ... LAST_CONNECTION => self.connection_writable(stream, io), - NODETABLE_RECEIVE => {}, + FIRST_SESSION ... LAST_SESSION => self.session_writable(stream, io), + FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_writable(stream, io), + DISCOVERY => { + self.discovery.lock().unwrap().as_mut().unwrap().writable(); + io.update_registration(DISCOVERY).expect("Error updating discovery registration"); + } _ => panic!("Received unknown writable token"), } } @@ -725,13 +873,25 @@ impl IoHandler> for Host where Messa fn timeout(&self, io: &IoContext>, token: TimerToken) { match token { IDLE => self.maintain_network(io), - FIRST_CONNECTION ... LAST_CONNECTION => self.connection_timeout(token, io), - NODETABLE_DISCOVERY => {}, - NODETABLE_MAINTAIN => {}, + INIT_PUBLIC => self.init_public_interface(io).unwrap_or_else(|e| + warn!("Error initializing public interface: {:?}", e)), + FIRST_SESSION ... LAST_SESSION => self.connection_timeout(token, io), + FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.connection_timeout(token, io), + DISCOVERY_REFRESH => { + self.discovery.lock().unwrap().as_mut().unwrap().refresh(); + io.update_registration(DISCOVERY).expect("Error updating discovery registration"); + }, + DISCOVERY_ROUND => { + let node_changes = { self.discovery.lock().unwrap().as_mut().unwrap().round() }; + if let Some(node_changes) = node_changes { + self.update_nodes(io, node_changes); + } + io.update_registration(DISCOVERY).expect("Error updating discovery registration"); + }, _ => match self.timers.read().unwrap().get(&token).cloned() { Some(timer) => match self.handlers.read().unwrap().get(timer.protocol).cloned() { - None => { warn!(target: "net", "No handler found for protocol: {:?}", timer.protocol) }, - Some(h) => { h.timeout(&NetworkContext::new(io, timer.protocol, None, self.connections.clone()), timer.token); } + None => { warn!(target: "network", "No handler found for protocol: {:?}", timer.protocol) }, + Some(h) => { h.timeout(&NetworkContext::new(io, timer.protocol, None, self.sessions.clone()), timer.token); } }, None => { warn!("Unknown timer token: {}", token); } // timer is not registerd through us } @@ -746,7 +906,7 @@ impl IoHandler> for Host where Messa ref versions } => { let h = handler.clone(); - h.initialize(&NetworkContext::new(io, protocol, None, self.connections.clone())); + h.initialize(&NetworkContext::new(io, protocol, None, self.sessions.clone())); self.handlers.write().unwrap().insert(protocol, h); let mut info = self.info.write().unwrap(); for v in versions { @@ -769,17 +929,15 @@ impl IoHandler> for Host where Messa io.register_timer(handler_token, *delay).expect("Error registering timer"); }, NetworkIoMessage::Disconnect(ref peer) => { - if let Some(connection) = self.connections.read().unwrap().get(*peer).cloned() { - match *connection.lock().unwrap().deref_mut() { - ConnectionEntry::Handshake(_) => {}, - ConnectionEntry::Session(ref mut s) => { s.disconnect(DisconnectReason::DisconnectRequested); } - } - } - self.kill_connection(*peer, io); + let session = { self.sessions.read().unwrap().get(*peer).cloned() }; + if let Some(session) = session { + session.lock().unwrap().disconnect(DisconnectReason::DisconnectRequested); + } + self.kill_connection(*peer, io, false); }, NetworkIoMessage::User(ref message) => { for (p, h) in self.handlers.read().unwrap().iter() { - h.message(&NetworkContext::new(io, p, None, self.connections.clone()), &message); + h.message(&NetworkContext::new(io, p, None, self.sessions.clone()), &message); } } } @@ -787,15 +945,19 @@ impl IoHandler> for Host where Messa fn register_stream(&self, stream: StreamToken, reg: Token, event_loop: &mut EventLoop>>) { match stream { - FIRST_CONNECTION ... LAST_CONNECTION => { - if let Some(connection) = self.connections.read().unwrap().get(stream).cloned() { - match *connection.lock().unwrap().deref() { - ConnectionEntry::Handshake(ref h) => h.register_socket(reg, event_loop).expect("Error registering socket"), - ConnectionEntry::Session(_) => warn!("Unexpected session stream registration") - } - } else {} // expired + FIRST_SESSION ... LAST_SESSION => { + let session = { self.sessions.read().unwrap().get(stream).cloned() }; + if let Some(session) = session { + session.lock().unwrap().register_socket(reg, event_loop).expect("Error registering socket"); + } } - NODETABLE_RECEIVE => event_loop.register(self.udp_socket.lock().unwrap().deref(), Token(NODETABLE_RECEIVE), EventSet::all(), PollOpt::edge()).expect("Error registering stream"), + FIRST_HANDSHAKE ... LAST_HANDSHAKE => { + let connection = { self.handshakes.read().unwrap().get(stream).cloned() }; + if let Some(connection) = connection { + connection.lock().unwrap().register_socket(reg, event_loop).expect("Error registering socket"); + } + } + DISCOVERY => self.discovery.lock().unwrap().as_ref().unwrap().register_socket(event_loop).expect("Error registering discovery socket"), TCP_ACCEPT => event_loop.register(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error registering stream"), _ => warn!("Unexpected stream registration") } @@ -803,35 +965,108 @@ impl IoHandler> for Host where Messa fn deregister_stream(&self, stream: StreamToken, event_loop: &mut EventLoop>>) { match stream { - FIRST_CONNECTION ... LAST_CONNECTION => { - let mut connections = self.connections.write().unwrap(); + FIRST_SESSION ... LAST_SESSION => { + let mut connections = self.sessions.write().unwrap(); if let Some(connection) = connections.get(stream).cloned() { - match *connection.lock().unwrap().deref() { - ConnectionEntry::Handshake(ref h) => h.deregister_socket(event_loop).expect("Error deregistering socket"), - ConnectionEntry::Session(ref s) => s.deregister_socket(event_loop).expect("Error deregistering session socket"), - } + connection.lock().unwrap().deregister_socket(event_loop).expect("Error deregistering socket"); connections.remove(stream); - } - }, - NODETABLE_RECEIVE => event_loop.deregister(self.udp_socket.lock().unwrap().deref()).unwrap(), - TCP_ACCEPT => event_loop.deregister(self.tcp_listener.lock().unwrap().deref()).unwrap(), + } + } + FIRST_HANDSHAKE ... LAST_HANDSHAKE => { + let mut connections = self.handshakes.write().unwrap(); + if let Some(connection) = connections.get(stream).cloned() { + connection.lock().unwrap().deregister_socket(event_loop).expect("Error deregistering socket"); + connections.remove(stream); + } + } + DISCOVERY => (), _ => warn!("Unexpected stream deregistration") } } fn update_stream(&self, stream: StreamToken, reg: Token, event_loop: &mut EventLoop>>) { match stream { - FIRST_CONNECTION ... LAST_CONNECTION => { - if let Some(connection) = self.connections.read().unwrap().get(stream).cloned() { - match *connection.lock().unwrap().deref() { - ConnectionEntry::Handshake(ref h) => h.update_socket(reg, event_loop).expect("Error updating socket"), - ConnectionEntry::Session(ref s) => s.update_socket(reg, event_loop).expect("Error updating socket"), - } - } else {} // expired + FIRST_SESSION ... LAST_SESSION => { + let connection = { self.sessions.read().unwrap().get(stream).cloned() }; + if let Some(connection) = connection { + connection.lock().unwrap().update_socket(reg, event_loop).expect("Error updating socket"); + } } - NODETABLE_RECEIVE => event_loop.reregister(self.udp_socket.lock().unwrap().deref(), Token(NODETABLE_RECEIVE), EventSet::all(), PollOpt::edge()).expect("Error reregistering stream"), + FIRST_HANDSHAKE ... LAST_HANDSHAKE => { + let connection = { self.handshakes.read().unwrap().get(stream).cloned() }; + if let Some(connection) = connection { + connection.lock().unwrap().update_socket(reg, event_loop).expect("Error updating socket"); + } + } + DISCOVERY => self.discovery.lock().unwrap().as_ref().unwrap().update_registration(event_loop).expect("Error reregistering discovery socket"), TCP_ACCEPT => event_loop.reregister(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error reregistering stream"), _ => warn!("Unexpected stream update") } } } + +fn save_key(path: &Path, key: &Secret) { + let mut path_buf = PathBuf::from(path); + if let Err(e) = fs::create_dir_all(path_buf.as_path()) { + warn!("Error creating key directory: {:?}", e); + return; + }; + path_buf.push("key"); + let mut file = match fs::File::create(path_buf.as_path()) { + Ok(file) => file, + Err(e) => { + warn!("Error creating key file: {:?}", e); + return; + } + }; + if let Err(e) = file.write(&key.hex().into_bytes()) { + warn!("Error writing key file: {:?}", e); + } +} + +fn load_key(path: &Path) -> Option { + let mut path_buf = PathBuf::from(path); + path_buf.push("key"); + let mut file = match fs::File::open(path_buf.as_path()) { + Ok(file) => file, + Err(e) => { + debug!("Error opening key file: {:?}", e); + return None; + } + }; + let mut buf = String::new(); + match file.read_to_string(&mut buf) { + Ok(_) => {}, + Err(e) => { + warn!("Error reading key file: {:?}", e); + return None; + } + } + match Secret::from_str(&buf) { + Ok(key) => Some(key), + Err(e) => { + warn!("Error parsing key file: {:?}", e); + None + } + } +} + +#[test] +fn key_save_load() { + use ::devtools::RandomTempPath; + let temp_path = RandomTempPath::create_dir(); + let key = H256::random(); + save_key(temp_path.as_path(), &key); + let r = load_key(temp_path.as_path()); + assert_eq!(key, r.unwrap()); +} + + +#[test] +fn host_client_url() { + let mut config = NetworkConfiguration::new(); + let key = h256_from_hex("6f7b0d801bc7b5ce7bbd930b84fd0369b3eb25d09be58d64ba811091046f3aa2"); + config.use_secret = Some(key); + let host: Host = Host::new(config).unwrap(); + assert!(host.local_url().starts_with("enode://101b3ef5a4ea7a1c7928e24c4c75fd053c235d7b80c22ae5c03d145d0ac7396e2a4ffff9adee3133a7b05044a5cee08115fd65145e5165d646bde371010d803c@")); +} diff --git a/util/src/network/ip_utils.rs b/util/src/network/ip_utils.rs new file mode 100644 index 000000000..27ff29737 --- /dev/null +++ b/util/src/network/ip_utils.rs @@ -0,0 +1,271 @@ +// 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 . + +// Based on original work by David Levy https://raw.githubusercontent.com/dlevy47/rust-interfaces + +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; +use std::io; +use igd::{PortMappingProtocol, search_gateway_from_timeout}; +use std::time::Duration; +use network::node_table::{NodeEndpoint}; + +pub enum IpAddr{ + V4(Ipv4Addr), + V6(Ipv6Addr), +} + +/// Socket address extension for rustc beta. To be replaces with now unstable API +pub trait SocketAddrExt { + /// Returns true for the special 'unspecified' address 0.0.0.0. + fn is_unspecified_s(&self) -> bool; + /// Returns true if the address appears to be globally routable. + fn is_global_s(&self) -> bool; +} + +impl SocketAddrExt for Ipv4Addr { + fn is_unspecified_s(&self) -> bool { + self.octets() == [0, 0, 0, 0] + } + + fn is_global_s(&self) -> bool { + !self.is_private() && !self.is_loopback() && !self.is_link_local() && + !self.is_broadcast() && !self.is_documentation() + } +} + +impl SocketAddrExt for Ipv6Addr { + fn is_unspecified_s(&self) -> bool { + self.segments() == [0, 0, 0, 0, 0, 0, 0, 0] + } + + fn is_global_s(&self) -> bool { + if self.is_multicast() { + self.segments()[0] & 0x000f == 14 + } else { + !self.is_loopback() && !((self.segments()[0] & 0xffc0) == 0xfe80) && + !((self.segments()[0] & 0xffc0) == 0xfec0) && !((self.segments()[0] & 0xfe00) == 0xfc00) + } + } +} + +#[cfg(not(windows))] +mod getinterfaces { + use std::{mem, io, ptr}; + use libc::{AF_INET, AF_INET6}; + use libc::{getifaddrs, freeifaddrs, ifaddrs, sockaddr, sockaddr_in, sockaddr_in6}; + use std::net::{Ipv4Addr, Ipv6Addr}; + use super::IpAddr; + + fn convert_sockaddr (sa: *mut sockaddr) -> Option { + if sa == ptr::null_mut() { return None; } + + let (addr, _) = match unsafe { *sa }.sa_family as i32 { + AF_INET => { + let sa: *const sockaddr_in = unsafe { mem::transmute(sa) }; + let sa = & unsafe { *sa }; + let (addr, port) = (sa.sin_addr.s_addr, sa.sin_port); + (IpAddr::V4(Ipv4Addr::new( + (addr & 0x000000FF) as u8, + ((addr & 0x0000FF00) >> 8) as u8, + ((addr & 0x00FF0000) >> 16) as u8, + ((addr & 0xFF000000) >> 24) as u8)), + port) + }, + AF_INET6 => { + let sa: *const sockaddr_in6 = unsafe { mem::transmute(sa) }; + let sa = & unsafe { *sa }; + let (addr, port) = (sa.sin6_addr.s6_addr, sa.sin6_port); + let addr: [u16; 8] = unsafe { mem::transmute(addr) }; + (IpAddr::V6(Ipv6Addr::new( + addr[0], + addr[1], + addr[2], + addr[3], + addr[4], + addr[5], + addr[6], + addr[7])), + port) + }, + _ => return None, + }; + Some(addr) + } + + fn convert_ifaddrs (ifa: *mut ifaddrs) -> Option { + let ifa = unsafe { &mut *ifa }; + convert_sockaddr(ifa.ifa_addr) + } + + pub fn get_all() -> io::Result> { + let mut ifap: *mut ifaddrs = unsafe { mem::zeroed() }; + if unsafe { getifaddrs(&mut ifap as *mut _) } != 0 { + return Err(io::Error::last_os_error()); + } + + let mut ret = Vec::new(); + let mut cur: *mut ifaddrs = ifap; + while cur != ptr::null_mut() { + if let Some(ip_addr) = convert_ifaddrs(cur) { + ret.push(ip_addr); + } + + //TODO: do something else maybe? + cur = unsafe { (*cur).ifa_next }; + } + + unsafe { freeifaddrs(ifap) }; + Ok(ret) + } +} + +#[cfg(not(windows))] +fn get_if_addrs() -> io::Result> { + getinterfaces::get_all() +} + +#[cfg(windows)] +fn get_if_addrs() -> io::Result> { + Ok(Vec::new()) +} + +/// Select the best available public address +pub fn select_public_address(port: u16) -> SocketAddr { + match get_if_addrs() { + Ok(list) => { + //prefer IPV4 bindings + for addr in &list { //TODO: use better criteria than just the first in the list + match *addr { + IpAddr::V4(a) if !a.is_unspecified_s() && !a.is_loopback() && !a.is_link_local() => { + return SocketAddr::V4(SocketAddrV4::new(a, port)); + }, + _ => {}, + } + } + for addr in list { + match addr { + IpAddr::V6(a) if !a.is_unspecified_s() && !a.is_loopback() => { + return SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)); + }, + _ => {}, + } + } + }, + Err(e) => debug!("Error listing public interfaces: {:?}", e) + } + SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port)) +} + +pub fn map_external_address(local: &NodeEndpoint) -> Option { + if let SocketAddr::V4(ref local_addr) = local.address { + match search_gateway_from_timeout(local_addr.ip().clone(), Duration::new(5, 0)) { + Err(ref err) => debug!("Gateway search error: {}", err), + Ok(gateway) => { + match gateway.get_external_ip() { + Err(ref err) => { + debug!("IP request error: {}", err); + }, + Ok(external_addr) => { + match gateway.add_any_port(PortMappingProtocol::TCP, SocketAddrV4::new(local_addr.ip().clone(), local_addr.port()), 0, "Parity Node/TCP") { + Err(ref err) => { + debug!("Port mapping error: {}", err); + }, + Ok(tcp_port) => { + match gateway.add_any_port(PortMappingProtocol::UDP, SocketAddrV4::new(local_addr.ip().clone(), local.udp_port), 0, "Parity Node/UDP") { + Err(ref err) => { + debug!("Port mapping error: {}", err); + }, + Ok(udp_port) => { + return Some(NodeEndpoint { address: SocketAddr::V4(SocketAddrV4::new(external_addr, tcp_port)), udp_port: udp_port }); + }, + } + }, + } + }, + } + }, + } + } + None +} + +#[test] +fn can_select_public_address() { + let pub_address = select_public_address(40477); + assert!(pub_address.port() == 40477); +} + +#[ignore] +#[test] +fn can_map_external_address_or_fail() { + let pub_address = select_public_address(40478); + let _ = map_external_address(&NodeEndpoint { address: pub_address, udp_port: 40478 }); +} + +#[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) { + let ip = Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]); + assert_eq!(octets, &ip.octets()); + + assert_eq!(ip.is_unspecified_s(), unspec); + assert_eq!(ip.is_loopback(), loopback); + assert_eq!(ip.is_private(), private); + assert_eq!(ip.is_link_local(), link_local); + assert_eq!(ip.is_global_s(), global); + assert_eq!(ip.is_multicast(), multicast); + assert_eq!(ip.is_broadcast(), broadcast); + assert_eq!(ip.is_documentation(), documentation); + } + + // address unspec loopbk privt linloc global multicast brdcast doc + check(&[0, 0, 0, 0], true, false, false, false, true, false, false, false); + check(&[0, 0, 0, 1], false, false, false, false, true, false, false, false); + check(&[1, 0, 0, 0], false, false, false, false, true, false, false, false); + check(&[10, 9, 8, 7], false, false, true, false, false, false, false, false); + check(&[127, 1, 2, 3], false, true, false, false, false, false, false, false); + check(&[172, 31, 254, 253], false, false, true, false, false, false, false, false); + check(&[169, 254, 253, 242], false, false, false, true, false, false, false, false); + check(&[192, 0, 2, 183], false, false, false, false, false, false, false, true); + check(&[192, 1, 2, 183], false, false, false, false, true, false, false, false); + check(&[192, 168, 254, 253], false, false, true, false, false, false, false, false); + check(&[198, 51, 100, 0], false, false, false, false, false, false, false, true); + check(&[203, 0, 113, 0], false, false, false, false, false, false, false, true); + check(&[203, 2, 113, 0], false, false, false, false, true, false, false, false); + check(&[224, 0, 0, 0], false, false, false, false, true, true, false, false); + check(&[239, 255, 255, 255], false, false, false, false, true, true, false, false); + check(&[255, 255, 255, 255], false, false, false, false, false, false, true, false); +} + +#[test] +fn ipv6_properties() { + fn check(str_addr: &str, unspec: bool, loopback: bool, global: bool) { + let ip: Ipv6Addr = str_addr.parse().unwrap(); + assert_eq!(str_addr, ip.to_string()); + + assert_eq!(ip.is_unspecified_s(), unspec); + assert_eq!(ip.is_loopback(), loopback); + assert_eq!(ip.is_global_s(), global); + } + + // unspec loopbk global + check("::", true, false, true); + check("::1", false, true, false); +} diff --git a/util/src/network/mod.rs b/util/src/network/mod.rs index 6b58c87eb..29f3d166c 100644 --- a/util/src/network/mod.rs +++ b/util/src/network/mod.rs @@ -56,7 +56,7 @@ //! } //! //! fn main () { -//! let mut service = NetworkService::::start(NetworkConfiguration::new()).expect("Error creating network service"); +//! let mut service = NetworkService::::start(NetworkConfiguration::new_local()).expect("Error creating network service"); //! service.register_protocol(Arc::new(MyHandler), "myproto", &[1u8]); //! //! // Wait for quit condition @@ -71,8 +71,9 @@ mod session; mod discovery; mod service; mod error; -mod node; +mod node_table; mod stats; +mod ip_utils; #[cfg(test)] mod tests; @@ -88,6 +89,9 @@ pub use network::host::NetworkConfiguration; pub use network::stats::NetworkStats; use io::TimerToken; +pub use network::node_table::is_valid_node_url; + +const PROTOCOL_VERSION: u32 = 4; /// Network IO protocol handler. This needs to be implemented for each new subprotocol. /// All the handler function are called from within IO event loop. diff --git a/util/src/network/node.rs b/util/src/network/node.rs deleted file mode 100644 index e23dee9f5..000000000 --- a/util/src/network/node.rs +++ /dev/null @@ -1,134 +0,0 @@ -// 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 std::net::{SocketAddr, ToSocketAddrs}; -use std::hash::{Hash, Hasher}; -use std::str::{FromStr}; -use hash::*; -use rlp::*; -use time::Tm; -use error::*; - -/// Node public key -pub type NodeId = H512; - -#[derive(Debug)] -/// Noe address info -pub struct NodeEndpoint { - /// IP(V4 or V6) address - pub address: SocketAddr, - /// Address as string (can be host name). - pub address_str: String, - /// Conneciton port. - pub udp_port: u16 -} - -impl FromStr for NodeEndpoint { - type Err = UtilError; - - /// Create endpoint from string. Performs name resolution if given a host name. - fn from_str(s: &str) -> Result { - let address = s.to_socket_addrs().map(|mut i| i.next()); - match address { - Ok(Some(a)) => Ok(NodeEndpoint { - address: a, - address_str: s.to_owned(), - udp_port: a.port() - }), - Ok(_) => Err(UtilError::AddressResolve(None)), - Err(e) => Err(UtilError::AddressResolve(Some(e))) - } - } -} - -#[derive(PartialEq, Eq, Copy, Clone)] -pub enum PeerType { - Required, - Optional -} - -pub struct Node { - pub id: NodeId, - pub endpoint: NodeEndpoint, - pub peer_type: PeerType, - pub last_attempted: Option, -} - -impl FromStr for Node { - type Err = UtilError; - fn from_str(s: &str) -> Result { - let (id, endpoint) = if &s[0..8] == "enode://" && s.len() > 136 && &s[136..137] == "@" { - (try!(NodeId::from_str(&s[8..136])), try!(NodeEndpoint::from_str(&s[137..]))) - } - else { - (NodeId::new(), try!(NodeEndpoint::from_str(s))) - }; - - Ok(Node { - id: id, - endpoint: endpoint, - peer_type: PeerType::Optional, - last_attempted: None, - }) - } -} - -impl PartialEq for Node { - fn eq(&self, other: &Self) -> bool { - self.id == other.id - } -} -impl Eq for Node { } - -impl Hash for Node { - fn hash(&self, state: &mut H) where H: Hasher { - self.id.hash(state) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::str::FromStr; - use std::net::*; - use hash::*; - - #[test] - fn endpoint_parse() { - let endpoint = NodeEndpoint::from_str("123.99.55.44:7770"); - assert!(endpoint.is_ok()); - let v4 = match endpoint.unwrap().address { - SocketAddr::V4(v4address) => v4address, - _ => panic!("should ve v4 address") - }; - assert_eq!(SocketAddrV4::new(Ipv4Addr::new(123, 99, 55, 44), 7770), v4); - } - - #[test] - fn node_parse() { - let node = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770"); - assert!(node.is_ok()); - let node = node.unwrap(); - let v4 = match node.endpoint.address { - SocketAddr::V4(v4address) => v4address, - _ => panic!("should ve v4 address") - }; - assert_eq!(SocketAddrV4::new(Ipv4Addr::new(22, 99, 55, 44), 7770), v4); - assert_eq!( - H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(), - node.id); - } -} diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs new file mode 100644 index 000000000..868863e8c --- /dev/null +++ b/util/src/network/node_table.rs @@ -0,0 +1,420 @@ +// 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 std::mem; +use std::slice::from_raw_parts; +use std::net::{SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr}; +use std::hash::{Hash, Hasher}; +use std::str::{FromStr}; +use std::collections::HashMap; +use std::fmt::{Display, Formatter}; +use std::path::{PathBuf}; +use std::fmt; +use std::fs; +use std::io::{Read, Write}; +use hash::*; +use rlp::*; +use time::Tm; +use error::*; +use network::discovery::{TableUpdates, NodeEntry}; +use network::ip_utils::*; +pub use rustc_serialize::json::Json; + +/// Node public key +pub type NodeId = H512; + +#[derive(Debug, Clone)] +/// Node address info +pub struct NodeEndpoint { + /// IP(V4 or V6) address + pub address: SocketAddr, + /// Conneciton port. + pub udp_port: u16 +} + +impl NodeEndpoint { + pub fn udp_address(&self) -> SocketAddr { + match self.address { + SocketAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a.ip().clone(), self.udp_port)), + SocketAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a.ip().clone(), self.udp_port, a.flowinfo(), a.scope_id())), + } + } +} + +impl NodeEndpoint { + pub fn from_rlp(rlp: &UntrustedRlp) -> Result { + let tcp_port = try!(rlp.val_at::(2)); + let udp_port = try!(rlp.val_at::(1)); + let addr_bytes = try!(try!(rlp.at(0)).data()); + let address = try!(match addr_bytes.len() { + 4 => Ok(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(addr_bytes[0], addr_bytes[1], addr_bytes[2], addr_bytes[3]), tcp_port))), + 16 => unsafe { + let o: *const u16 = mem::transmute(addr_bytes.as_ptr()); + let o = from_raw_parts(o, 8); + Ok(SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7]), tcp_port, 0, 0))) + }, + _ => Err(DecoderError::RlpInconsistentLengthAndData) + }); + Ok(NodeEndpoint { address: address, udp_port: udp_port }) + } + + pub fn to_rlp(&self, rlp: &mut RlpStream) { + match self.address { + SocketAddr::V4(a) => { + rlp.append(&(&a.ip().octets()[..])); + } + SocketAddr::V6(a) => unsafe { + let o: *const u8 = mem::transmute(a.ip().segments().as_ptr()); + rlp.append(&from_raw_parts(o, 16)); + } + }; + rlp.append(&self.udp_port); + rlp.append(&self.address.port()); + } + + pub fn to_rlp_list(&self, rlp: &mut RlpStream) { + rlp.begin_list(3); + self.to_rlp(rlp); + } + + pub fn is_valid(&self) -> bool { + self.udp_port != 0 && self.address.port() != 0 && + match self.address { + SocketAddr::V4(a) => !a.ip().is_unspecified_s(), + SocketAddr::V6(a) => !a.ip().is_unspecified_s() + } + } + + pub fn is_global(&self) -> bool { + match self.address { + SocketAddr::V4(a) => a.ip().is_global_s(), + SocketAddr::V6(a) => a.ip().is_global_s() + } + } +} + +impl FromStr for NodeEndpoint { + type Err = UtilError; + + /// Create endpoint from string. Performs name resolution if given a host name. + fn from_str(s: &str) -> Result { + let address = s.to_socket_addrs().map(|mut i| i.next()); + match address { + Ok(Some(a)) => Ok(NodeEndpoint { + address: a, + udp_port: a.port() + }), + Ok(_) => Err(UtilError::AddressResolve(None)), + Err(e) => Err(UtilError::AddressResolve(Some(e))) + } + } +} + +#[derive(PartialEq, Eq, Copy, Clone)] +pub enum PeerType { + _Required, + Optional +} + +pub struct Node { + pub id: NodeId, + pub endpoint: NodeEndpoint, + pub peer_type: PeerType, + pub failures: u32, + pub last_attempted: Option, +} + +impl Node { + pub fn new(id: NodeId, endpoint: NodeEndpoint) -> Node { + Node { + id: id, + endpoint: endpoint, + peer_type: PeerType::Optional, + failures: 0, + last_attempted: None, + } + } +} + +impl Display for Node { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + if self.endpoint.udp_port != self.endpoint.address.port() { + try!(write!(f, "enode://{}@{}+{}", self.id.hex(), self.endpoint.address, self.endpoint.udp_port)); + } else { + try!(write!(f, "enode://{}@{}", self.id.hex(), self.endpoint.address)); + } + Ok(()) + } +} + +impl FromStr for Node { + type Err = UtilError; + fn from_str(s: &str) -> Result { + let (id, endpoint) = if s.len() > 136 && &s[0..8] == "enode://" && &s[136..137] == "@" { + (try!(NodeId::from_str(&s[8..136])), try!(NodeEndpoint::from_str(&s[137..]))) + } + else { + (NodeId::new(), try!(NodeEndpoint::from_str(s))) + }; + + Ok(Node { + id: id, + endpoint: endpoint, + peer_type: PeerType::Optional, + last_attempted: None, + failures: 0, + }) + } +} + +impl PartialEq for Node { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} +impl Eq for Node {} + +impl Hash for Node { + fn hash(&self, state: &mut H) where H: Hasher { + self.id.hash(state) + } +} + +/// Node table backed by disk file. +pub struct NodeTable { + nodes: HashMap, + path: Option, +} + +impl NodeTable { + pub fn new(path: Option) -> NodeTable { + NodeTable { + path: path.clone(), + nodes: NodeTable::load(path), + } + } + + /// Add a node to table + pub fn add_node(&mut self, mut node: Node) { + // preserve failure counter + let failures = self.nodes.get(&node.id).map_or(0, |n| n.failures); + node.failures = failures; + self.nodes.insert(node.id.clone(), node); + } + + /// Returns node ids sorted by number of failures + pub fn nodes(&self) -> Vec { + let mut refs: Vec<&Node> = self.nodes.values().collect(); + refs.sort_by(|a, b| a.failures.cmp(&b.failures)); + refs.iter().map(|n| n.id.clone()).collect() + } + + /// Unordered list of all entries + pub fn unordered_entries(&self) -> Vec { + // preserve failure counter + self.nodes.values().map(|n| NodeEntry { endpoint: n.endpoint.clone(), id: n.id.clone() }).collect() + } + + /// Get particular node + pub fn get_mut(&mut self, id: &NodeId) -> Option<&mut Node> { + self.nodes.get_mut(id) + } + + /// Apply table changes coming from discovery + pub fn update(&mut self, mut update: TableUpdates) { + for (_, node) in update.added.drain() { + let mut entry = self.nodes.entry(node.id.clone()).or_insert_with(|| Node::new(node.id.clone(), node.endpoint.clone())); + entry.endpoint = node.endpoint; + } + for r in update.removed { + self.nodes.remove(&r); + } + } + + /// Increase failure counte for a node + pub fn note_failure(&mut self, id: &NodeId) { + if let Some(node) = self.nodes.get_mut(id) { + node.failures += 1; + } + } + + fn save(&self) { + if let Some(ref path) = self.path { + let mut path_buf = PathBuf::from(path); + if let Err(e) = fs::create_dir_all(path_buf.as_path()) { + warn!("Error creating node table directory: {:?}", e); + return; + }; + path_buf.push("nodes.json"); + let mut json = String::new(); + json.push_str("{\n"); + json.push_str("\"nodes\": [\n"); + let node_ids = self.nodes(); + for i in 0 .. node_ids.len() { + let node = self.nodes.get(&node_ids[i]).unwrap(); + json.push_str(&format!("\t{{ \"url\": \"{}\", \"failures\": {} }}{}\n", node, node.failures, if i == node_ids.len() - 1 {""} else {","})) + } + json.push_str("]\n"); + json.push_str("}"); + let mut file = match fs::File::create(path_buf.as_path()) { + Ok(file) => file, + Err(e) => { + warn!("Error creating node table file: {:?}", e); + return; + } + }; + if let Err(e) = file.write(&json.into_bytes()) { + warn!("Error writing node table file: {:?}", e); + } + } + } + + fn load(path: Option) -> HashMap { + let mut nodes: HashMap = HashMap::new(); + if let Some(path) = path { + let mut path_buf = PathBuf::from(path); + path_buf.push("nodes.json"); + let mut file = match fs::File::open(path_buf.as_path()) { + Ok(file) => file, + Err(e) => { + debug!("Error opening node table file: {:?}", e); + return nodes; + } + }; + let mut buf = String::new(); + match file.read_to_string(&mut buf) { + Ok(_) => {}, + Err(e) => { + warn!("Error reading node table file: {:?}", e); + return nodes; + } + } + let json = match Json::from_str(&buf) { + Ok(json) => json, + Err(e) => { + warn!("Error parsing node table file: {:?}", e); + return nodes; + } + }; + if let Some(list) = json.as_object().and_then(|o| o.get("nodes")).and_then(|n| n.as_array()) { + for n in list.iter().filter_map(|n| n.as_object()) { + if let Some(url) = n.get("url").and_then(|u| u.as_string()) { + if let Ok(mut node) = Node::from_str(url) { + if let Some(failures) = n.get("failures").and_then(|f| f.as_u64()) { + node.failures = failures as u32; + } + nodes.insert(node.id.clone(), node); + } + } + } + } + } + nodes + } +} + +impl Drop for NodeTable { + fn drop(&mut self) { + self.save(); + } +} + +/// Check if node url is valid +pub fn is_valid_node_url(url: &str) -> bool { + use std::str::FromStr; + Node::from_str(url).is_ok() +} + +#[cfg(test)] +mod tests { + use super::*; + use std::str::FromStr; + use std::net::*; + use hash::*; + use devtools::*; + + #[test] + fn endpoint_parse() { + let endpoint = NodeEndpoint::from_str("123.99.55.44:7770"); + assert!(endpoint.is_ok()); + let v4 = match endpoint.unwrap().address { + SocketAddr::V4(v4address) => v4address, + _ => panic!("should ve v4 address") + }; + assert_eq!(SocketAddrV4::new(Ipv4Addr::new(123, 99, 55, 44), 7770), v4); + } + + #[test] + fn node_parse() { + assert!(is_valid_node_url("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770")); + let node = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770"); + assert!(node.is_ok()); + let node = node.unwrap(); + let v4 = match node.endpoint.address { + SocketAddr::V4(v4address) => v4address, + _ => panic!("should ve v4 address") + }; + assert_eq!(SocketAddrV4::new(Ipv4Addr::new(22, 99, 55, 44), 7770), v4); + assert_eq!( + H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(), + node.id); + } + + #[test] + fn table_failure_order() { + let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); + let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); + let node3 = Node::from_str("enode://c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); + let id1 = H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); + let id2 = H512::from_str("b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); + let id3 = H512::from_str("c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); + let mut table = NodeTable::new(None); + table.add_node(node3); + table.add_node(node1); + table.add_node(node2); + + table.note_failure(&id1); + table.note_failure(&id1); + table.note_failure(&id2); + + let r = table.nodes(); + assert_eq!(r[0][..], id3[..]); + assert_eq!(r[1][..], id2[..]); + assert_eq!(r[2][..], id1[..]); + } + + #[test] + fn table_save_load() { + let temp_path = RandomTempPath::create_dir(); + let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); + let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap(); + let id1 = H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); + let id2 = H512::from_str("b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap(); + { + let mut table = NodeTable::new(Some(temp_path.as_path().to_str().unwrap().to_owned())); + table.add_node(node1); + table.add_node(node2); + table.note_failure(&id2); + } + + { + let table = NodeTable::new(Some(temp_path.as_path().to_str().unwrap().to_owned())); + let r = table.nodes(); + assert_eq!(r[0][..], id1[..]); + assert_eq!(r[1][..], id2[..]); + } + } +} diff --git a/util/src/network/service.rs b/util/src/network/service.rs index 60f0ec415..49957f7e7 100644 --- a/util/src/network/service.rs +++ b/util/src/network/service.rs @@ -28,6 +28,7 @@ use io::*; pub struct NetworkService where Message: Send + Sync + Clone + 'static { io_service: IoService>, host_info: String, + host: Arc>, stats: Arc, panic_handler: Arc } @@ -39,16 +40,16 @@ impl NetworkService where Message: Send + Sync + Clone + 'stat let mut io_service = try!(IoService::>::start()); panic_handler.forward_from(&io_service); - let host = Arc::new(Host::new(config)); + let host = Arc::new(try!(Host::new(config))); let stats = host.stats().clone(); let host_info = host.client_version(); - info!("Host ID={:?}", host.client_id()); - try!(io_service.register_handler(host)); + try!(io_service.register_handler(host.clone())); Ok(NetworkService { io_service: io_service, host_info: host_info, stats: stats, - panic_handler: panic_handler + panic_handler: panic_handler, + host: host, }) } @@ -72,12 +73,21 @@ impl NetworkService where Message: Send + Sync + Clone + 'stat &mut self.io_service } - /// Returns underlying io service. + /// Returns network statistics. pub fn stats(&self) -> &NetworkStats { &self.stats } -} + /// Returns external url if available. + pub fn external_url(&self) -> Option { + self.host.external_url() + } + + /// Returns external url if available. + pub fn local_url(&self) -> String { + self.host.local_url() + } +} impl MayPanic for NetworkService where Message: Send + Sync + Clone + 'static { fn on_panic(&self, closure: F) where F: OnPanicListener { diff --git a/util/src/network/session.rs b/util/src/network/session.rs index c4ebe7a2a..7dbcc4229 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::net::SocketAddr; +use std::io; use mio::*; use hash::*; use rlp::*; @@ -23,7 +25,7 @@ use error::*; use io::{IoContext, StreamToken}; use network::error::{NetworkError, DisconnectReason}; use network::host::*; -use network::node::NodeId; +use network::node_table::NodeId; use time; const PING_TIMEOUT_SEC: u64 = 30; @@ -39,6 +41,8 @@ pub struct Session { connection: EncryptedConnection, /// Session ready flag. Set after successfull Hello packet exchange had_hello: bool, + /// Session is no longer active flag. + expired: bool, ping_time_ns: u64, pong_time_ns: Option, } @@ -89,7 +93,7 @@ impl Decodable for PeerCapabilityInfo { } } -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug)] struct SessionCapabilityInfo { pub protocol: &'static str, pub version: u8, @@ -107,8 +111,9 @@ const PACKET_USER: u8 = 0x10; const PACKET_LAST: u8 = 0x7f; impl Session { - /// Create a new session out of comepleted handshake. Consumes handshake object. - pub fn new(h: Handshake, _io: &IoContext, host: &HostInfo) -> Result where Message: Send + Sync + Clone { + /// Create a new session out of comepleted handshake. This clones the handshake connection object + /// and leaves the handhsake in limbo to be deregistered from the event loop. + pub fn new(h: &mut Handshake, host: &HostInfo) -> Result { let id = h.id.clone(); let connection = try!(EncryptedConnection::new(h)); let mut session = Session { @@ -123,19 +128,48 @@ impl Session { }, ping_time_ns: 0, pong_time_ns: None, + expired: false, }; try!(session.write_hello(host)); try!(session.send_ping()); Ok(session) } + /// Get id of the remote peer + pub fn id(&self) -> &NodeId { + &self.info.id + } + /// Check if session is ready to send/receive data pub fn is_ready(&self) -> bool { self.had_hello } + /// Mark this session as inactive to be deleted lated. + pub fn set_expired(&mut self) { + self.expired = true; + } + + /// Check if this session is expired. + pub fn expired(&self) -> bool { + self.expired + } + + /// Replace socket token + pub fn set_token(&mut self, token: StreamToken) { + self.connection.set_token(token); + } + + /// Get remote peer address + pub fn remote_addr(&self) -> io::Result { + self.connection.remote_addr() + } + /// Readable IO handler. Returns packet data if available. pub fn readable(&mut self, io: &IoContext, host: &HostInfo) -> Result where Message: Send + Sync + Clone { + if self.expired() { + return Ok(SessionData::None) + } match try!(self.connection.readable(io)) { Some(data) => Ok(try!(self.read_packet(data, host))), None => Ok(SessionData::None) @@ -144,6 +178,9 @@ impl Session { /// Writable IO handler. Sends pending packets. pub fn writable(&mut self, io: &IoContext, _host: &HostInfo) -> Result<(), UtilError> where Message: Send + Sync + Clone { + if self.expired() { + return Ok(()) + } self.connection.writable(io) } @@ -152,8 +189,20 @@ impl Session { self.info.capabilities.iter().any(|c| c.protocol == protocol) } + /// Register the session socket with the event loop + pub fn register_socket>(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { + if self.expired() { + return Ok(()); + } + try!(self.connection.register_socket(reg, event_loop)); + Ok(()) + } + /// Update registration with the event loop. Should be called at the end of the IO handler. pub fn update_socket(&self, reg:Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { + if self.expired() { + return Ok(()); + } self.connection.update_socket(reg, event_loop) } @@ -164,6 +213,13 @@ impl Session { /// Send a protocol packet to peer. pub fn send_packet(&mut self, protocol: &str, packet_id: u8, data: &[u8]) -> Result<(), UtilError> { + if self.info.capabilities.is_empty() || !self.had_hello { + debug!(target: "network", "Sending to unconfirmed session {}, protocol: {}, packet: {}", self.token(), protocol, packet_id); + return Err(From::from(NetworkError::BadProtocol)); + } + if self.expired() { + return Err(From::from(NetworkError::Expired)); + } let mut i = 0usize; while protocol != self.info.capabilities[i].protocol { i += 1; @@ -214,7 +270,11 @@ impl Session { try!(self.read_hello(&rlp, host)); Ok(SessionData::Ready) }, - PACKET_DISCONNECT => Err(From::from(NetworkError::Disconnect(DisconnectReason::DisconnectRequested))), + PACKET_DISCONNECT => { + let rlp = UntrustedRlp::new(&packet.data[1..]); + let reason: u8 = try!(rlp.val_at(0)); + Err(From::from(NetworkError::Disconnect(DisconnectReason::from_u8(reason)))) + } PACKET_PING => { try!(self.send_pong()); Ok(SessionData::None) @@ -255,7 +315,7 @@ impl Session { .append(&host.protocol_version) .append(&host.client_version) .append(&host.capabilities) - .append(&host.listen_port) + .append(&host.local_endpoint.address.port()) .append(host.id()); self.connection.send_packet(&rlp.out()) } @@ -298,10 +358,15 @@ impl Session { offset += caps[i].packet_count; i += 1; } - trace!(target: "net", "Hello: {} v{} {} {:?}", client_version, protocol, id, caps); + trace!(target: "network", "Hello: {} v{} {} {:?}", client_version, protocol, id, caps); self.info.client_version = client_version; self.info.capabilities = caps; + if self.info.capabilities.is_empty() { + trace!(target: "network", "No common capabilities with peer."); + return Err(From::from(self.disconnect(DisconnectReason::UselessPeer))); + } if protocol != host.protocol_version { + trace!(target: "network", "Peer protocol version mismatch: {}", protocol); return Err(From::from(self.disconnect(DisconnectReason::UselessPeer))); } self.had_hello = true; diff --git a/util/src/network/tests.rs b/util/src/network/tests.rs index c1b59df9b..b43da9320 100644 --- a/util/src/network/tests.rs +++ b/util/src/network/tests.rs @@ -23,17 +23,10 @@ use io::TimerToken; use crypto::KeyPair; pub struct TestProtocol { + drop_session: bool, pub packet: Mutex, pub got_timeout: AtomicBool, -} - -impl Default for TestProtocol { - fn default() -> Self { - TestProtocol { - packet: Mutex::new(Vec::new()), - got_timeout: AtomicBool::new(false), - } - } + pub got_disconnect: AtomicBool, } #[derive(Clone)] @@ -42,9 +35,17 @@ pub struct TestProtocolMessage { } impl TestProtocol { + pub fn new(drop_session: bool) -> Self { + TestProtocol { + packet: Mutex::new(Vec::new()), + got_timeout: AtomicBool::new(false), + got_disconnect: AtomicBool::new(false), + drop_session: drop_session, + } + } /// Creates and register protocol with the network service - pub fn register(service: &mut NetworkService) -> Arc { - let handler = Arc::new(TestProtocol::default()); + pub fn register(service: &mut NetworkService, drop_session: bool) -> Arc { + let handler = Arc::new(TestProtocol::new(drop_session)); service.register_protocol(handler.clone(), "test", &[42u8, 43u8]).expect("Error registering test protocol handler"); handler } @@ -56,6 +57,10 @@ impl TestProtocol { pub fn got_timeout(&self) -> bool { self.got_timeout.load(AtomicOrdering::Relaxed) } + + pub fn got_disconnect(&self) -> bool { + self.got_disconnect.load(AtomicOrdering::Relaxed) + } } impl NetworkProtocolHandler for TestProtocol { @@ -68,15 +73,22 @@ impl NetworkProtocolHandler for TestProtocol { self.packet.lock().unwrap().extend(data); } - fn connected(&self, io: &NetworkContext, _peer: &PeerId) { - io.respond(33, "hello".to_owned().into_bytes()).unwrap(); + fn connected(&self, io: &NetworkContext, peer: &PeerId) { + assert!(io.peer_info(*peer).contains("Parity")); + if self.drop_session { + io.disconnect_peer(*peer) + } else { + io.respond(33, "hello".to_owned().into_bytes()).unwrap(); + } } fn disconnected(&self, _io: &NetworkContext, _peer: &PeerId) { + self.got_disconnect.store(true, AtomicOrdering::Relaxed); } /// Timer function called after a timeout created with `NetworkContext::timeout`. - fn timeout(&self, _io: &NetworkContext, timer: TimerToken) { + fn timeout(&self, io: &NetworkContext, timer: TimerToken) { + io.message(TestProtocolMessage { payload: 22 }); assert_eq!(timer, 0); self.got_timeout.store(true, AtomicOrdering::Relaxed); } @@ -85,34 +97,55 @@ impl NetworkProtocolHandler for TestProtocol { #[test] fn net_service() { - let mut service = NetworkService::::start(NetworkConfiguration::new()).expect("Error creating network service"); - service.register_protocol(Arc::new(TestProtocol::default()), "myproto", &[1u8]).unwrap(); + let mut service = NetworkService::::start(NetworkConfiguration::new_local()).expect("Error creating network service"); + service.register_protocol(Arc::new(TestProtocol::new(false)), "myproto", &[1u8]).unwrap(); } #[test] fn net_connect() { + ::log::init_log(); let key1 = KeyPair::create().unwrap(); - let mut config1 = NetworkConfiguration::new_with_port(30344); + let mut config1 = NetworkConfiguration::new_local(); config1.use_secret = Some(key1.secret().clone()); config1.boot_nodes = vec![ ]; - let mut config2 = NetworkConfiguration::new_with_port(30345); - config2.boot_nodes = vec![ format!("enode://{}@127.0.0.1:30344", key1.public().hex()) ]; let mut service1 = NetworkService::::start(config1).unwrap(); + let handler1 = TestProtocol::register(&mut service1, false); + let mut config2 = NetworkConfiguration::new_local(); + info!("net_connect: local URL: {}", service1.local_url()); + config2.boot_nodes = vec![ service1.local_url() ]; let mut service2 = NetworkService::::start(config2).unwrap(); - let handler1 = TestProtocol::register(&mut service1); - let handler2 = TestProtocol::register(&mut service2); - while !handler1.got_packet() && !handler2.got_packet() { + let handler2 = TestProtocol::register(&mut service2, false); + while !handler1.got_packet() && !handler2.got_packet() && (service1.stats().sessions() == 0 || service2.stats().sessions() == 0) { thread::sleep(Duration::from_millis(50)); } assert!(service1.stats().sessions() >= 1); assert!(service2.stats().sessions() >= 1); } +#[test] +fn net_disconnect() { + let key1 = KeyPair::create().unwrap(); + let mut config1 = NetworkConfiguration::new_local(); + config1.use_secret = Some(key1.secret().clone()); + config1.boot_nodes = vec![ ]; + let mut service1 = NetworkService::::start(config1).unwrap(); + let handler1 = TestProtocol::register(&mut service1, false); + let mut config2 = NetworkConfiguration::new_local(); + config2.boot_nodes = vec![ service1.local_url() ]; + let mut service2 = NetworkService::::start(config2).unwrap(); + let handler2 = TestProtocol::register(&mut service2, true); + while !(handler1.got_disconnect() && handler2.got_disconnect()) { + thread::sleep(Duration::from_millis(50)); + } + assert!(handler1.got_disconnect()); + assert!(handler2.got_disconnect()); +} + #[test] fn net_timeout() { - let config = NetworkConfiguration::new_with_port(30346); + let config = NetworkConfiguration::new_local(); let mut service = NetworkService::::start(config).unwrap(); - let handler = TestProtocol::register(&mut service); + let handler = TestProtocol::register(&mut service, false); while !handler.got_timeout() { thread::sleep(Duration::from_millis(50)); } diff --git a/util/src/nibbleslice.rs b/util/src/nibbleslice.rs index 047990368..e10def40a 100644 --- a/util/src/nibbleslice.rs +++ b/util/src/nibbleslice.rs @@ -69,13 +69,13 @@ impl<'a> Iterator for NibbleSliceIterator<'a> { impl<'a, 'view> NibbleSlice<'a> where 'a: 'view { /// Create a new nibble slice with the given byte-slice. - pub fn new(data: &[u8]) -> NibbleSlice { NibbleSlice::new_offset(data, 0) } + pub fn new(data: &'a [u8]) -> Self { NibbleSlice::new_offset(data, 0) } /// Create a new nibble slice with the given byte-slice with a nibble offset. - pub fn new_offset(data: &'a [u8], offset: usize) -> NibbleSlice { NibbleSlice{data: data, offset: offset, data_encode_suffix: &b""[..], offset_encode_suffix: 0} } + pub fn new_offset(data: &'a [u8], offset: usize) -> Self { NibbleSlice{data: data, offset: offset, data_encode_suffix: &b""[..], offset_encode_suffix: 0} } /// Create a composed nibble slice; one followed by the other. - pub fn new_composed(a: &'a NibbleSlice, b: &'a NibbleSlice) -> NibbleSlice<'a> { NibbleSlice{data: a.data, offset: a.offset, data_encode_suffix: b.data, offset_encode_suffix: b.offset} } + pub fn new_composed(a: &'a NibbleSlice, b: &'a NibbleSlice) -> Self { NibbleSlice{data: a.data, offset: a.offset, data_encode_suffix: b.data, offset_encode_suffix: b.offset} } /*pub fn new_composed_bytes_offset(a: &NibbleSlice, b: &NibbleSlice) -> (Bytes, usize) { let r: Vec::with_capacity((a.len() + b.len() + 1) / 2); diff --git a/util/src/numbers.rs b/util/src/numbers.rs new file mode 100644 index 000000000..b79338fc1 --- /dev/null +++ b/util/src/numbers.rs @@ -0,0 +1,20 @@ +// 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 . + +//! Utils number types. + +pub use hash::*; +pub use bigint::uint::*; diff --git a/util/src/overlaydb.rs b/util/src/overlaydb.rs index f8e9c3eee..b5dec75e2 100644 --- a/util/src/overlaydb.rs +++ b/util/src/overlaydb.rs @@ -26,7 +26,7 @@ use std::ops::*; use std::sync::*; use std::env; use std::collections::HashMap; -use rocksdb::{DB, Writable, IteratorMode}; +use kvdb::{Database, DBTransaction}; /// Implementation of the HashDB trait for a disk-backed database with a memory overlay. /// @@ -36,17 +36,18 @@ use rocksdb::{DB, Writable, IteratorMode}; /// /// `lookup()` and `contains()` maintain normal behaviour - all `insert()` and `remove()` /// queries have an immediate effect in terms of these functions. +#[derive(Clone)] pub struct OverlayDB { overlay: MemoryDB, - backing: Arc, + backing: Arc, } impl OverlayDB { /// Create a new instance of OverlayDB given a `backing` database. - pub fn new(backing: DB) -> OverlayDB { Self::new_with_arc(Arc::new(backing)) } + pub fn new(backing: Database) -> OverlayDB { Self::new_with_arc(Arc::new(backing)) } /// Create a new instance of OverlayDB given a `backing` database. - pub fn new_with_arc(backing: Arc) -> OverlayDB { + pub fn new_with_arc(backing: Arc) -> OverlayDB { OverlayDB{ overlay: MemoryDB::new(), backing: backing } } @@ -54,7 +55,37 @@ impl OverlayDB { pub fn new_temp() -> OverlayDB { let mut dir = env::temp_dir(); dir.push(H32::random().hex()); - Self::new(DB::open_default(dir.to_str().unwrap()).unwrap()) + Self::new(Database::open_default(dir.to_str().unwrap()).unwrap()) + } + + /// Commit all operations to given batch. + pub fn commit_to_batch(&mut self, batch: &DBTransaction) -> Result { + let mut ret = 0u32; + let mut deletes = 0usize; + for i in self.overlay.drain().into_iter() { + let (key, (value, rc)) = i; + if rc != 0 { + match self.payload(&key) { + Some(x) => { + let (back_value, back_rc) = x; + let total_rc: i32 = back_rc as i32 + rc; + if total_rc < 0 { + return Err(From::from(BaseDataError::NegativelyReferencedHash(key))); + } + deletes += if self.put_payload_in_batch(batch, &key, (back_value, total_rc as u32)) {1} else {0}; + } + None => { + if rc < 0 { + return Err(From::from(BaseDataError::NegativelyReferencedHash(key))); + } + self.put_payload_in_batch(batch, &key, (value, rc as u32)); + } + }; + ret += 1; + } + } + trace!("OverlayDB::commit() deleted {} nodes", deletes); + Ok(ret) } /// Commit all memory operations to the backing database. @@ -95,13 +126,13 @@ impl OverlayDB { let (back_value, back_rc) = x; let total_rc: i32 = back_rc as i32 + rc; if total_rc < 0 { - return Err(From::from(BaseDataError::NegativelyReferencedHash)); + return Err(From::from(BaseDataError::NegativelyReferencedHash(key))); } deletes += if self.put_payload(&key, (back_value, total_rc as u32)) {1} else {0}; } None => { if rc < 0 { - return Err(From::from(BaseDataError::NegativelyReferencedHash)); + return Err(From::from(BaseDataError::NegativelyReferencedHash(key))); } self.put_payload(&key, (value, rc as u32)); } @@ -136,6 +167,9 @@ impl OverlayDB { /// ``` pub fn revert(&mut self) { self.overlay.clear(); } + /// Get the number of references that would be committed. + pub fn commit_refs(&self, key: &H256) -> i32 { self.overlay.raw(&key).map_or(0, |&(_, refs)| refs) } + /// Get the refs and value of the given key. fn payload(&self, key: &H256) -> Option<(Bytes, u32)> { self.backing.get(&key.bytes()) @@ -146,7 +180,21 @@ impl OverlayDB { }) } - /// Get the refs and value of the given key. + /// Put the refs and value of the given key, possibly deleting it from the db. + fn put_payload_in_batch(&self, batch: &DBTransaction, key: &H256, payload: (Bytes, u32)) -> bool { + if payload.1 > 0 { + let mut s = RlpStream::new_list(2); + s.append(&payload.1); + s.append(&payload.0); + batch.put(&key.bytes(), s.as_raw()).expect("Low-level database error. Some issue with your hard disk?"); + false + } else { + batch.delete(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?"); + true + } + } + + /// Put the refs and value of the given key, possibly deleting it from the db. fn put_payload(&self, key: &H256, payload: (Bytes, u32)) -> bool { if payload.1 > 0 { let mut s = RlpStream::new_list(2); @@ -164,7 +212,7 @@ impl OverlayDB { impl HashDB for OverlayDB { fn keys(&self) -> HashMap { let mut ret: HashMap = HashMap::new(); - for (key, _) in self.backing.iterator(IteratorMode::Start) { + for (key, _) in self.backing.iter() { let h = H256::from_slice(key.deref()); let r = self.payload(&h).unwrap().1; ret.insert(h, r as i32); @@ -318,7 +366,7 @@ fn overlaydb_complex() { fn playpen() { use std::fs; { - let db: DB = DB::open_default("/tmp/test").unwrap(); + let db: Database = Database::open_default("/tmp/test").unwrap(); db.put(b"test", b"test2").unwrap(); match db.get(b"test") { Ok(Some(value)) => println!("Got value {:?}", value.deref()), diff --git a/util/src/panics.rs b/util/src/panics.rs index 27dd605f0..980d4fc69 100644 --- a/util/src/panics.rs +++ b/util/src/panics.rs @@ -18,8 +18,8 @@ use std::thread; use std::ops::DerefMut; -use std::any::Any; use std::sync::{Arc, Mutex}; +use std::default::Default; /// Thread-safe closure for handling possible panics pub trait OnPanicListener: Send + Sync + 'static { @@ -40,19 +40,37 @@ pub trait MayPanic { fn on_panic(&self, closure: F) where F: OnPanicListener; } +struct PanicGuard<'a> { + handler: &'a PanicHandler, +} + +impl<'a> Drop for PanicGuard<'a> { + fn drop(&mut self) { + if thread::panicking() { + self.handler.notify_all("Panic!".to_owned()); + } + } +} + /// Structure that allows to catch panics and notify listeners pub struct PanicHandler { listeners: Mutex>> } +impl Default for PanicHandler { + fn default() -> Self { + PanicHandler::new() + } +} + impl PanicHandler { /// Creates new `PanicHandler` wrapped in `Arc` - pub fn new_in_arc() -> Arc { + pub fn new_in_arc() -> Arc { Arc::new(Self::new()) } /// Creates new `PanicHandler` - pub fn new() -> PanicHandler { + pub fn new() -> Self { PanicHandler { listeners: Mutex::new(vec![]) } @@ -60,19 +78,11 @@ impl PanicHandler { /// Invoke closure and catch any possible panics. /// In case of panic notifies all listeners about it. - #[allow(deprecated)] - // TODO [todr] catch_panic is deprecated but panic::recover has different bounds (not allowing mutex) + #[cfg_attr(feature="dev", allow(deprecated))] pub fn catch_panic(&self, g: G) -> thread::Result where G: FnOnce() -> R + Send + 'static { - let result = thread::catch_panic(g); - - if let Err(ref e) = result { - let res = convert_to_string(e); - if let Some(r) = res { - self.notify_all(r); - } - } - - result + let _guard = PanicGuard { handler: self }; + let result = g(); + Ok(result) } fn notify_all(&self, r: String) { @@ -103,14 +113,8 @@ impl OnPanicListener for F } } -fn convert_to_string(t: &Box) -> Option { - let as_str = t.downcast_ref::<&'static str>().cloned().map(|t| t.to_owned()); - let as_string = t.downcast_ref::().cloned(); - - as_str.or(as_string) -} - #[test] +#[ignore] // panic forwarding doesnt work on the same thread in beta fn should_notify_listeners_about_panic () { use std::sync::RwLock; // given @@ -127,6 +131,7 @@ fn should_notify_listeners_about_panic () { } #[test] +#[ignore] // panic forwarding doesnt work on the same thread in beta fn should_notify_listeners_about_panic_when_string_is_dynamic () { use std::sync::RwLock; // given @@ -164,6 +169,7 @@ fn should_notify_listeners_about_panic_in_other_thread () { } #[test] +#[ignore] // panic forwarding doesnt work on the same thread in beta fn should_forward_panics () { use std::sync::RwLock; // given diff --git a/util/src/rlp/bytes.rs b/util/src/rlp/bytes.rs index 3b25c09ae..e8bfa57b0 100644 --- a/util/src/rlp/bytes.rs +++ b/util/src/rlp/bytes.rs @@ -21,7 +21,7 @@ use std::mem; use std::fmt; use std::cmp::Ordering; use std::error::Error as StdError; -use uint::{Uint, U128, U256}; +use bigint::uint::{Uint, U128, U256}; use hash::FixedHash; use elastic_array::*; @@ -232,12 +232,12 @@ impl_uint_from_bytes!(u64); impl_uint_from_bytes!(usize); macro_rules! impl_uint_from_bytes { - ($name: ident) => { + ($name: ident, $size: expr) => { impl FromBytes for $name { fn from_bytes(bytes: &[u8]) -> FromBytesResult<$name> { if !bytes.is_empty() && bytes[0] == 0 { Err(FromBytesError::ZeroPrefixedInt) - } else if bytes.len() <= $name::SIZE { + } else if bytes.len() <= $size { Ok($name::from(bytes)) } else { Err(FromBytesError::DataIsTooLong) @@ -247,8 +247,8 @@ macro_rules! impl_uint_from_bytes { } } -impl_uint_from_bytes!(U256); -impl_uint_from_bytes!(U128); +impl_uint_from_bytes!(U256, 32); +impl_uint_from_bytes!(U128, 16); impl FromBytes for T where T: FixedHash { fn from_bytes(bytes: &[u8]) -> FromBytesResult { diff --git a/util/src/rlp/rlpin.rs b/util/src/rlp/rlpin.rs index 8f3e26712..945ae9b24 100644 --- a/util/src/rlp/rlpin.rs +++ b/util/src/rlp/rlpin.rs @@ -116,7 +116,7 @@ impl<'a, 'view> View<'a, 'view> for Rlp<'a> where 'a: 'view { impl <'a, 'view> Rlp<'a> where 'a: 'view { fn view_as_val(r: &R) -> T where R: View<'a, 'view>, T: RlpDecodable { let res: Result = r.as_val(); - res.unwrap_or_else(|_| panic!()) + res.unwrap_or_else(|e| panic!("DecodeError: {}", e)) } /// Decode into an object diff --git a/util/src/rlp/rlpstream.rs b/util/src/rlp/rlpstream.rs index ba70e7b2b..7bf3d3cdd 100644 --- a/util/src/rlp/rlpstream.rs +++ b/util/src/rlp/rlpstream.rs @@ -15,6 +15,7 @@ // along with Parity. If not, see . use std::ops::Deref; +use std::default::Default; use elastic_array::*; use rlp::bytes::{ToBytes, VecLike}; use rlp::{Stream, Encoder, Encodable}; @@ -44,6 +45,12 @@ pub struct RlpStream { finished_list: bool, } +impl Default for RlpStream { + fn default() -> Self { + RlpStream::new() + } +} + impl Stream for RlpStream { fn new() -> Self { RlpStream { @@ -190,8 +197,14 @@ struct BasicEncoder { bytes: ElasticArray1024, } +impl Default for BasicEncoder { + fn default() -> Self { + BasicEncoder::new() + } +} + impl BasicEncoder { - fn new() -> BasicEncoder { + fn new() -> Self { BasicEncoder { bytes: ElasticArray1024::new() } } @@ -222,7 +235,7 @@ impl Encoder for BasicEncoder { // just 0 0 => self.bytes.push(0x80u8), // byte is its own encoding if < 0x80 - 1 => { + 1 => { value.to_bytes(&mut self.bytes); let len = self.bytes.len(); let last_byte = self.bytes[len - 1]; diff --git a/util/src/rlp/tests.rs b/util/src/rlp/tests.rs index eb2039103..a92dd5c4a 100644 --- a/util/src/rlp/tests.rs +++ b/util/src/rlp/tests.rs @@ -21,7 +21,7 @@ use std::{fmt, cmp}; use std::str::FromStr; use rlp; use rlp::{UntrustedRlp, RlpStream, View, Stream, DecoderError}; -use uint::U256; +use bigint::uint::U256; #[test] fn rlp_at() { diff --git a/util/src/rlp/untrusted_rlp.rs b/util/src/rlp/untrusted_rlp.rs index 463d5cb2f..957a09b61 100644 --- a/util/src/rlp/untrusted_rlp.rs +++ b/util/src/rlp/untrusted_rlp.rs @@ -429,7 +429,6 @@ impl Decodable for Option where T: Decodable { macro_rules! impl_array_decodable { ($index_type:ty, $len:expr ) => ( impl Decodable for [T; $len] where T: Decodable { - #[allow(len_zero)] fn decode(decoder: &D) -> Result where D: Decoder { let decoders = decoder.as_rlp(); diff --git a/util/src/semantic_version.rs b/util/src/semantic_version.rs index 496ff2318..b550cd829 100644 --- a/util/src/semantic_version.rs +++ b/util/src/semantic_version.rs @@ -16,13 +16,13 @@ //! Semantic version formatting and comparing. -/// A version value with strict meaning. Use `to_u32` to convert to a simple integer. -/// +/// A version value with strict meaning. Use `as_u32` to convert to a simple integer. +/// /// # Example /// ``` /// extern crate ethcore_util as util; /// use util::semantic_version::*; -/// +/// /// fn main() { /// assert_eq!(SemanticVersion::new(1, 2, 3).as_u32(), 0x010203); /// } diff --git a/util/src/table.rs b/util/src/table.rs new file mode 100644 index 000000000..c3b2006cf --- /dev/null +++ b/util/src/table.rs @@ -0,0 +1,265 @@ +// 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 . + +//! A collection associating pair of keys (row and column) with a single value. + +use std::default::Default; +use std::hash::Hash; +use std::collections::HashMap; + +/// Structure to hold double-indexed values +/// +/// You can obviously use `HashMap<(Row,Col), Val>`, but this structure gives +/// you better access to all `Columns` in Specific `Row`. Namely you can get sub-hashmap +/// `HashMap` for specific `Row` +pub struct Table + where Row: Eq + Hash + Clone, + Col: Eq + Hash { + map: HashMap>, +} + +impl Default for Table + where Row: Eq + Hash + Clone, + Col: Eq + Hash { + fn default() -> Self { + Table::new() + } +} + +// There is default but clippy does not detect it? +#[cfg_attr(feature="dev", allow(new_without_default))] +impl Table + where Row: Eq + Hash + Clone, + Col: Eq + Hash { + /// Creates new Table + pub fn new() -> Self { + Table { + map: HashMap::new(), + } + } + + /// Removes all elements from this Table + pub fn clear(&mut self) { + self.map.clear(); + } + + /// Returns length of the Table (number of (row, col, val) tuples) + pub fn len(&self) -> usize { + self.map.values().fold(0, |acc, v| acc + v.len()) + } + + /// Check if there is any element in this Table + pub fn is_empty(&self) -> bool { + self.map.is_empty() || self.map.values().all(|v| v.is_empty()) + } + + /// Get mutable reference for single Table row. + pub fn row_mut(&mut self, row: &Row) -> Option<&mut HashMap> { + self.map.get_mut(row) + } + + /// Checks if row is defined for that table (note that even if defined it might be empty) + pub fn has_row(&self, row: &Row) -> bool { + self.map.contains_key(row) + } + + /// Get immutable reference for single row in this Table + pub fn row(&self, row: &Row) -> Option<&HashMap> { + self.map.get(row) + } + + /// Get element in cell described by `(row, col)` + pub fn get(&self, row: &Row, col: &Col) -> Option<&Val> { + self.map.get(row).and_then(|r| r.get(col)) + } + + /// Remove value from specific cell + /// + /// It will remove the row if it's the last value in it + pub fn remove(&mut self, row: &Row, col: &Col) -> Option { + let (val, is_empty) = { + let row_map = self.map.get_mut(row); + if let None = row_map { + return None; + } + let mut row_map = row_map.unwrap(); + let val = row_map.remove(col); + (val, row_map.is_empty()) + }; + // Clean row + if is_empty { + self.map.remove(row); + } + val + } + + /// Remove given row from Table if there are no values defined in it + /// + /// When using `#row_mut` it may happen that all values from some row are drained. + /// Table however will not be aware that row is empty. + /// You can use this method to explicitly remove row entry from the Table. + pub fn clear_if_empty(&mut self, row: &Row) { + let is_empty = self.map.get(row).map_or(false, |m| m.is_empty()); + if is_empty { + self.map.remove(row); + } + } + + /// Inserts new value to specified cell + /// + /// Returns previous value (if any) + pub fn insert(&mut self, row: Row, col: Col, val: Val) -> Option { + self.map.entry(row).or_insert_with(HashMap::new).insert(col, val) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn should_create_empty_table() { + // when + let table : Table = Table::new(); + + // then + assert!(table.is_empty()); + assert_eq!(table.len(), 0); + } + + #[test] + fn should_insert_elements_and_return_previous_if_any() { + // given + let mut table = Table::new(); + + // when + let r1 = table.insert(5, 4, true); + let r2 = table.insert(10, 4, true); + let r3 = table.insert(10, 10, true); + let r4 = table.insert(10, 10, false); + + // then + assert!(r1.is_none()); + assert!(r2.is_none()); + assert!(r3.is_none()); + assert!(r4.is_some()); + assert!(!table.is_empty()); + assert_eq!(r4.unwrap(), true); + assert_eq!(table.len(), 3); + } + + #[test] + fn should_remove_element() { + // given + let mut table = Table::new(); + table.insert(5, 4, true); + assert!(!table.is_empty()); + assert_eq!(table.len(), 1); + + // when + let r = table.remove(&5, &4); + + // then + assert!(table.is_empty()); + assert_eq!(table.len() ,0); + assert_eq!(r.unwrap(), true); + } + + #[test] + fn should_return_none_if_trying_to_remove_non_existing_element() { + // given + let mut table : Table = Table::new(); + assert!(table.is_empty()); + + // when + let r = table.remove(&5, &4); + + // then + assert!(r.is_none()); + } + + #[test] + fn should_clear_row_if_removing_last_element() { + // given + let mut table = Table::new(); + table.insert(5, 4, true); + assert!(table.has_row(&5)); + + // when + let r = table.remove(&5, &4); + + // then + assert!(r.is_some()); + assert!(!table.has_row(&5)); + } + + #[test] + fn should_return_element_given_row_and_col() { + // given + let mut table = Table::new(); + table.insert(1551, 1234, 123); + + // when + let r1 = table.get(&1551, &1234); + let r2 = table.get(&5, &4); + + // then + assert!(r1.is_some()); + assert!(r2.is_none()); + assert_eq!(r1.unwrap(), &123); + } + + #[test] + fn should_clear_table() { + // given + let mut table = Table::new(); + table.insert(1, 1, true); + table.insert(1, 2, false); + table.insert(2, 2, false); + assert_eq!(table.len(), 3); + + // when + table.clear(); + + // then + assert!(table.is_empty()); + assert_eq!(table.len(), 0); + assert_eq!(table.has_row(&1), false); + assert_eq!(table.has_row(&2), false); + } + + #[test] + fn should_return_mutable_row() { + // given + let mut table = Table::new(); + table.insert(1, 1, true); + table.insert(1, 2, false); + table.insert(2, 2, false); + + // when + { + let mut row = table.row_mut(&1).unwrap(); + row.remove(&1); + row.remove(&2); + } + assert!(table.has_row(&1)); + table.clear_if_empty(&1); + + // then + assert!(!table.has_row(&1)); + assert_eq!(table.len(), 1); + } +} diff --git a/util/src/tests/helpers.rs b/util/src/tests/helpers.rs deleted file mode 100644 index fee3d2cbb..000000000 --- a/util/src/tests/helpers.rs +++ /dev/null @@ -1,31 +0,0 @@ -use common::*; -use std::path::PathBuf; -use std::fs::{remove_dir_all}; -use std::env; - -pub struct RandomTempPath { - path: PathBuf -} - -impl RandomTempPath { - pub fn create_dir() -> RandomTempPath { - let mut dir = env::temp_dir(); - dir.push(H32::random().hex()); - fs::create_dir_all(dir.as_path()).unwrap(); - RandomTempPath { - path: dir.clone() - } - } - - pub fn as_path(&self) -> &PathBuf { - &self.path - } -} - -impl Drop for RandomTempPath { - fn drop(&mut self) { - if let Err(e) = remove_dir_all(self.as_path()) { - panic!("failed to remove temp directory, probably something failed to destroyed ({})", e); - } - } -} diff --git a/util/src/tests/mod.rs b/util/src/tests/mod.rs deleted file mode 100644 index 1630fabcd..000000000 --- a/util/src/tests/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod helpers; diff --git a/util/src/trie/journal.rs b/util/src/trie/journal.rs index db16a313d..4ffd7cf5c 100644 --- a/util/src/trie/journal.rs +++ b/util/src/trie/journal.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::default::Default; use sha3::*; use hash::H256; use bytes::*; @@ -39,6 +40,12 @@ pub struct Score { #[derive(Debug)] pub struct Journal (Vec); +impl Default for Journal { + fn default() -> Self { + Journal::new() + } +} + impl Journal { /// Create a new, empty, object. pub fn new() -> Journal { Journal(vec![]) } diff --git a/util/src/trie/standardmap.rs b/util/src/trie/standardmap.rs index 98a5ae0f0..b7f3a9500 100644 --- a/util/src/trie/standardmap.rs +++ b/util/src/trie/standardmap.rs @@ -20,6 +20,7 @@ extern crate rand; use bytes::*; use sha3::*; use hash::*; +use rlp::encode; /// Alphabet to use when creating words for insertion into tries. pub enum Alphabet { @@ -39,6 +40,8 @@ pub enum ValueMode { Mirror, /// Randomly (50:50) 1 or 32 byte randomly string. Random, + /// RLP-encoded index. + Index, } /// Standard test map for profiling tries. @@ -89,19 +92,27 @@ impl StandardMap { /// Create the standard map (set of keys and values) for the object's fields. pub fn make(&self) -> Vec<(Bytes, Bytes)> { + self.make_with(&mut H256::new()) + } + + /// Create the standard map (set of keys and values) for the object's fields, using the given seed. + pub fn make_with(&self, seed: &mut H256) -> Vec<(Bytes, Bytes)> { let low = b"abcdef"; let mid = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; let mut d: Vec<(Bytes, Bytes)> = Vec::new(); - let mut seed = H256::new(); - for _ in 0..self.count { + for index in 0..self.count { let k = match self.alphabet { - Alphabet::All => Self::random_bytes(self.min_key, self.journal_key, &mut seed), - Alphabet::Low => Self::random_word(low, self.min_key, self.journal_key, &mut seed), - Alphabet::Mid => Self::random_word(mid, self.min_key, self.journal_key, &mut seed), - Alphabet::Custom(ref a) => Self::random_word(&a, self.min_key, self.journal_key, &mut seed), + Alphabet::All => Self::random_bytes(self.min_key, self.journal_key, seed), + Alphabet::Low => Self::random_word(low, self.min_key, self.journal_key, seed), + Alphabet::Mid => Self::random_word(mid, self.min_key, self.journal_key, seed), + Alphabet::Custom(ref a) => Self::random_word(&a, self.min_key, self.journal_key, seed), + }; + let v = match self.value_mode { + ValueMode::Mirror => k.clone(), + ValueMode::Random => Self::random_value(seed), + ValueMode::Index => encode(&index).to_vec(), }; - let v = match self.value_mode { ValueMode::Mirror => k.clone(), ValueMode::Random => Self::random_value(&mut seed) }; d.push((k, v)) } d diff --git a/util/src/trie/triedb.rs b/util/src/trie/triedb.rs index e7884a177..06076d273 100644 --- a/util/src/trie/triedb.rs +++ b/util/src/trie/triedb.rs @@ -22,7 +22,7 @@ use super::trietraits::*; use super::node::*; /// A `Trie` implementation using a generic `HashDB` backing database. -/// +/// /// Use it as a `Trie` trait object. You can use `db()` to get the backing database object, `keys` /// to get the keys belonging to the trie in the backing database, and `db_items_remaining()` to get /// which items in the backing database do not belong to this trie. If this is the only trie in the @@ -54,7 +54,7 @@ pub struct TrieDB<'db> { pub hash_count: usize, } -#[allow(wrong_self_convention)] +#[cfg_attr(feature="dev", allow(wrong_self_convention))] impl<'db> TrieDB<'db> { /// Create a new trie with the backing database `db` and `root` /// Panics, if `root` does not exist @@ -63,16 +63,16 @@ impl<'db> TrieDB<'db> { flushln!("TrieDB::new({}): Trie root not found!", root); panic!("Trie root not found!"); } - TrieDB { - db: db, + TrieDB { + db: db, root: root, - hash_count: 0 + hash_count: 0 } } /// Get the backing database. - pub fn db(&'db self) -> &'db HashDB { - self.db + pub fn db(&'db self) -> &'db HashDB { + self.db } /// Determine all the keys in the backing database that belong to the trie. @@ -142,7 +142,7 @@ impl<'db> TrieDB<'db> { /// Indentation helper for `formal_all`. fn fmt_indent(&self, f: &mut fmt::Formatter, size: usize) -> fmt::Result { - for _ in 0..size { + for _ in 0..size { try!(write!(f, " ")); } Ok(()) @@ -358,7 +358,7 @@ impl<'db> fmt::Debug for TrieDB<'db> { fn iterator() { use memorydb::*; use super::triedbmut::*; - + let d = vec![ &b"A"[..], &b"AA"[..], &b"AB"[..], &b"B"[..] ]; let mut memdb = MemoryDB::new(); diff --git a/util/src/trie/triedbmut.rs b/util/src/trie/triedbmut.rs index 8e92063aa..3d75fa3e1 100644 --- a/util/src/trie/triedbmut.rs +++ b/util/src/trie/triedbmut.rs @@ -23,7 +23,7 @@ use super::journal::*; use super::trietraits::*; /// A `Trie` implementation using a generic `HashDB` backing database. -/// +/// /// Use it as a `Trie` trait object. You can use `db()` to get the backing database object, `keys` /// to get the keys belonging to the trie in the backing database, and `db_items_remaining()` to get /// which items in the backing database do not belong to this trie. If this is the only trie in the @@ -66,21 +66,21 @@ enum MaybeChanged<'a> { Changed(Bytes), } -#[allow(wrong_self_convention)] +#[cfg_attr(feature="dev", allow(wrong_self_convention))] impl<'db> TrieDBMut<'db> { /// Create a new trie with the backing database `db` and empty `root` /// Initialise to the state entailed by the genesis block. /// This guarantees the trie is built correctly. - pub fn new(db: &'db mut HashDB, root: &'db mut H256) -> Self { + pub fn new(db: &'db mut HashDB, root: &'db mut H256) -> Self { let mut r = TrieDBMut{ - db: db, + db: db, root: root, - hash_count: 0 - }; + hash_count: 0 + }; // set root rlp - *r.root = SHA3_NULL_RLP.clone(); - r + *r.root = SHA3_NULL_RLP.clone(); + r } /// Create a new trie with the backing database `db` and `root`. @@ -91,21 +91,21 @@ impl<'db> TrieDBMut<'db> { flushln!("Trie root not found {}", root); panic!("Trie root not found!"); } - TrieDBMut { - db: db, + TrieDBMut { + db: db, root: root, - hash_count: 0 + hash_count: 0 } } /// Get the backing database. - pub fn db(&'db self) -> &'db HashDB { - self.db + pub fn db(&'db self) -> &'db HashDB { + self.db } /// Get the backing database. - pub fn db_mut(&'db mut self) -> &'db mut HashDB { - self.db + pub fn db_mut(&'db mut self) -> &'db mut HashDB { + self.db } /// Determine all the keys in the backing database that belong to the trie. @@ -184,7 +184,7 @@ impl<'db> TrieDBMut<'db> { /// Indentation helper for `formal_all`. fn fmt_indent(&self, f: &mut fmt::Formatter, size: usize) -> fmt::Result { - for _ in 0..size { + for _ in 0..size { try!(write!(f, " ")); } Ok(()) @@ -350,7 +350,7 @@ impl<'db> TrieDBMut<'db> { } } - #[allow(cyclomatic_complexity)] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] /// Determine the RLP of the node, assuming we're inserting `partial` into the /// node currently of data `old`. This will *not* delete any hash of `old` from the database; /// it will just return the new RLP that includes the new node. @@ -378,7 +378,7 @@ impl<'db> TrieDBMut<'db> { // original had empty slot - place a leaf there. true if old_rlp.at(i).is_empty() => journal.new_node(Self::compose_leaf(&partial.mid(1), value), &mut s), // original has something there already; augment. - true => { + true => { let new = self.augmented(self.take_node(&old_rlp.at(i), journal), &partial.mid(1), value, journal); journal.new_node(new, &mut s); } @@ -687,31 +687,10 @@ mod tests { use super::*; use nibbleslice::*; use rlp::*; - use rand::random; - use std::collections::HashSet; - use bytes::{ToPretty,Bytes,Populatable}; + use bytes::ToPretty; use super::super::node::*; use super::super::trietraits::*; - - fn random_key(alphabet: &[u8], min_count: usize, journal_count: usize) -> Vec { - let mut ret: Vec = Vec::new(); - let r = min_count + if journal_count > 0 {random::() % journal_count} else {0}; - for _ in 0..r { - ret.push(alphabet[random::() % alphabet.len()]); - } - ret - } - - fn random_value_indexed(j: usize) -> Bytes { - match random::() % 2 { - 0 => encode(&j).to_vec(), - _ => { - let mut h = H256::new(); - h.as_slice_mut()[31] = j as u8; - encode(&h).to_vec() - }, - } - } + use super::super::standardmap::*; fn populate_trie<'db>(db: &'db mut HashDB, root: &'db mut H256, v: &[(Vec, Vec)]) -> TrieDBMut<'db> { let mut t = TrieDBMut::new(db, root); @@ -756,20 +735,18 @@ mod tests { };*/ // panic!(); + let mut seed = H256::new(); for test_i in 0..1 { if test_i % 50 == 0 { debug!("{:?} of 10000 stress tests done", test_i); } - let mut x: Vec<(Vec, Vec)> = Vec::new(); - let mut got: HashSet> = HashSet::new(); - let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; - for j in 0..100usize { - let key = random_key(alphabet, 5, 0); - if !got.contains(&key) { - x.push((key.clone(), random_value_indexed(j))); - got.insert(key); - } - } + let x = StandardMap { + alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), + min_key: 5, + journal_key: 0, + value_mode: ValueMode::Index, + count: 100, + }.make_with(&mut seed); let real = trie_root(x.clone()); let mut memdb = MemoryDB::new(); @@ -1049,13 +1026,16 @@ mod tests { #[test] fn stress() { + let mut seed = H256::new(); for _ in 0..50 { - let mut x: Vec<(Vec, Vec)> = Vec::new(); - let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; - for j in 0..4u32 { - let key = random_key(alphabet, 5, 1); - x.push((key, encode(&j).to_vec())); - } + let x = StandardMap { + alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), + min_key: 5, + journal_key: 0, + value_mode: ValueMode::Index, + count: 4, + }.make_with(&mut seed); + let real = trie_root(x.clone()); let mut memdb = MemoryDB::new(); let mut root = H256::new(); diff --git a/util/src/uint.rs b/util/src/uint.rs deleted file mode 100644 index c3e15a581..000000000 --- a/util/src/uint.rs +++ /dev/null @@ -1,1390 +0,0 @@ -// 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 . - -// Code derived from original work by Andrew Poelstra - -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Big unsigned integer types -//! -//! Implementation of a various large-but-fixed sized unsigned integer types. -//! The functions here are designed to be fast. -//! - -use standard::*; -use from_json::*; -use rustc_serialize::hex::ToHex; -use serde; - -macro_rules! impl_map_from { - ($thing:ident, $from:ty, $to:ty) => { - impl From<$from> for $thing { - fn from(value: $from) -> $thing { - From::from(value as $to) - } - } - } -} - -macro_rules! overflowing { - ($op: expr, $overflow: expr) => ( - { - let (overflow_x, overflow_overflow) = $op; - $overflow |= overflow_overflow; - overflow_x - } - ); - ($op: expr) => ( - { - let (overflow_x, _overflow_overflow) = $op; - overflow_x - } - ); -} - -macro_rules! panic_on_overflow { - ($name: expr) => { - if $name { - panic!("arithmetic operation overflow") - } - } -} - -/// Large, fixed-length unsigned integer type. -pub trait Uint: Sized + Default + FromStr + From + FromJson + fmt::Debug + fmt::Display + PartialOrd + Ord + PartialEq + Eq + Hash { - - /// Size of this type. - const SIZE: usize; - - /// Returns new instance equalling zero. - fn zero() -> Self; - /// Returns new instance equalling one. - fn one() -> Self; - - /// Error type for converting from a decimal string. - type FromDecStrErr; - /// Convert from a decimal string. - fn from_dec_str(value: &str) -> Result; - - /// Conversion to u32 - fn low_u32(&self) -> u32; - - /// Conversion to u64 - fn low_u64(&self) -> u64; - - /// Conversion to u32 with overflow checking - fn as_u32(&self) -> u32; - - /// Conversion to u64 with overflow checking - fn as_u64(&self) -> u64; - - /// Return the least number of bits needed to represent the number - fn bits(&self) -> usize; - /// Return if specific bit is set - fn bit(&self, index: usize) -> bool; - /// Return single byte - fn byte(&self, index: usize) -> u8; - /// Get this Uint as slice of bytes - fn to_bytes(&self, bytes: &mut[u8]); - - /// Create `Uint(10**n)` - fn exp10(n: usize) -> Self; - /// Return eponentation `self**other`. Panic on overflow. - fn pow(self, other: Self) -> Self; - /// Return wrapped eponentation `self**other` and flag if there was an overflow - fn overflowing_pow(self, other: Self) -> (Self, bool); - - /// Add this `Uint` to other returning result and possible overflow - fn overflowing_add(self, other: Self) -> (Self, bool); - - /// Subtract another `Uint` from this returning result and possible overflow - fn overflowing_sub(self, other: Self) -> (Self, bool); - - /// Multiple this `Uint` with other returning result and possible overflow - fn overflowing_mul(self, other: Self) -> (Self, bool); - - /// Divide this `Uint` by other returning result and possible overflow - fn overflowing_div(self, other: Self) -> (Self, bool); - - /// Returns reminder of division of this `Uint` by other and possible overflow - fn overflowing_rem(self, other: Self) -> (Self, bool); - - /// Returns negation of this `Uint` and overflow (always true) - fn overflowing_neg(self) -> (Self, bool); - - /// Shifts this `Uint` and returns overflow - fn overflowing_shl(self, shift: u32) -> (Self, bool); -} - -macro_rules! construct_uint { - ($name:ident, $n_words:expr) => ( - /// Little-endian large integer type - #[derive(Copy, Clone, Eq, PartialEq)] - pub struct $name(pub [u64; $n_words]); - - impl Uint for $name { - const SIZE: usize = $n_words * 8; - - type FromDecStrErr = FromHexError; - - /// TODO: optimize, throw appropriate err - fn from_dec_str(value: &str) -> Result { - Ok(value.bytes() - .map(|b| b - 48) - .fold($name::from(0u64), | acc, c | - // fast multiplication by 10 - // (acc << 3) + (acc << 1) => acc * 10 - (acc << 3) + (acc << 1) + $name::from(c) - )) - } - - #[inline] - fn low_u32(&self) -> u32 { - let &$name(ref arr) = self; - arr[0] as u32 - } - - #[inline] - fn low_u64(&self) -> u64 { - let &$name(ref arr) = self; - arr[0] - } - - /// Conversion to u32 with overflow checking - #[inline] - fn as_u32(&self) -> u32 { - let &$name(ref arr) = self; - if (arr[0] & (0xffffffffu64 << 32)) != 0 { - panic!("Integer overflow when casting U256") - } - self.as_u64() as u32 - } - - /// Conversion to u64 with overflow checking - #[inline] - fn as_u64(&self) -> u64 { - let &$name(ref arr) = self; - for i in 1..$n_words { - if arr[i] != 0 { - panic!("Integer overflow when casting U256") - } - } - arr[0] - } - - /// Return the least number of bits needed to represent the number - #[inline] - fn bits(&self) -> usize { - let &$name(ref arr) = self; - for i in 1..$n_words { - if arr[$n_words - i] > 0 { return (0x40 * ($n_words - i + 1)) - arr[$n_words - i].leading_zeros() as usize; } - } - 0x40 - arr[0].leading_zeros() as usize - } - - #[inline] - fn bit(&self, index: usize) -> bool { - let &$name(ref arr) = self; - arr[index / 64] & (1 << (index % 64)) != 0 - } - - #[inline] - fn byte(&self, index: usize) -> u8 { - let &$name(ref arr) = self; - (arr[index / 8] >> (((index % 8)) * 8)) as u8 - } - - fn to_bytes(&self, bytes: &mut[u8]) { - assert!($n_words * 8 == bytes.len()); - let &$name(ref arr) = self; - for i in 0..bytes.len() { - let rev = bytes.len() - 1 - i; - let pos = rev / 8; - bytes[i] = (arr[pos] >> ((rev % 8) * 8)) as u8; - } - } - - #[inline] - fn exp10(n: usize) -> Self { - match n { - 0 => Self::from(1u64), - _ => Self::exp10(n - 1) * Self::from(10u64) - } - } - - #[inline] - fn zero() -> Self { - From::from(0u64) - } - - #[inline] - fn one() -> Self { - From::from(1u64) - } - - /// Fast exponentation by squaring - /// https://en.wikipedia.org/wiki/Exponentiation_by_squaring - fn pow(self, expon: Self) -> Self { - if expon == Self::zero() { - return Self::one() - } - let is_even = |x : &Self| x.low_u64() & 1 == 0; - - let u_one = Self::one(); - let u_two = Self::from(2); - let mut y = u_one; - let mut n = expon; - let mut x = self; - while n > u_one { - if is_even(&n) { - x = x * x; - n = n / u_two; - } else { - y = x * y; - x = x * x; - n = (n - u_one) / u_two; - } - } - x * y - } - - /// Fast exponentation by squaring - /// https://en.wikipedia.org/wiki/Exponentiation_by_squaring - fn overflowing_pow(self, expon: Self) -> (Self, bool) { - if expon == Self::zero() { - return (Self::one(), false) - } - let is_even = |x : &Self| x.low_u64() & 1 == 0; - - let u_one = Self::one(); - let u_two = Self::from(2); - let mut y = u_one; - let mut n = expon; - let mut x = self; - let mut overflow = false; - - while n > u_one { - if is_even(&n) { - x = overflowing!(x.overflowing_mul(x), overflow); - n = n / u_two; - } else { - y = overflowing!(x.overflowing_mul(y), overflow); - x = overflowing!(x.overflowing_mul(x), overflow); - n = (n - u_one) / u_two; - } - } - let res = overflowing!(x.overflowing_mul(y), overflow); - (res, overflow) - } - - fn overflowing_add(self, other: $name) -> ($name, bool) { - let $name(ref me) = self; - let $name(ref you) = other; - let mut ret = [0u64; $n_words]; - let mut carry = [0u64; $n_words]; - let mut b_carry = false; - let mut overflow = false; - - for i in 0..$n_words { - ret[i] = me[i].wrapping_add(you[i]); - - if ret[i] < me[i] { - if i < $n_words - 1 { - carry[i + 1] = 1; - b_carry = true; - } else { - overflow = true; - } - } - } - if b_carry { - let ret = overflowing!($name(ret).overflowing_add($name(carry)), overflow); - (ret, overflow) - } else { - ($name(ret), overflow) - } - } - - fn overflowing_sub(self, other: $name) -> ($name, bool) { - let res = overflowing!((!other).overflowing_add(From::from(1u64))); - let res = overflowing!(self.overflowing_add(res)); - (res, self < other) - } - - fn overflowing_mul(self, other: $name) -> ($name, bool) { - let mut res = $name::from(0u64); - let mut overflow = false; - // TODO: be more efficient about this - for i in 0..(2 * $n_words) { - let v = overflowing!(self.overflowing_mul_u32((other >> (32 * i)).low_u32()), overflow); - let res2 = overflowing!(v.overflowing_shl(32 * i as u32), overflow); - res = overflowing!(res.overflowing_add(res2), overflow); - } - (res, overflow) - } - - fn overflowing_div(self, other: $name) -> ($name, bool) { - (self / other, false) - } - - fn overflowing_rem(self, other: $name) -> ($name, bool) { - (self % other, false) - } - - fn overflowing_neg(self) -> ($name, bool) { - (!self, true) - } - - fn overflowing_shl(self, shift32: u32) -> ($name, bool) { - let $name(ref original) = self; - let mut ret = [0u64; $n_words]; - let shift = shift32 as usize; - let word_shift = shift / 64; - let bit_shift = shift % 64; - for i in 0..$n_words { - // Shift - if i + word_shift < $n_words { - ret[i + word_shift] += original[i] << bit_shift; - } - // Carry - if bit_shift > 0 && i + word_shift + 1 < $n_words { - ret[i + word_shift + 1] += original[i] >> (64 - bit_shift); - } - } - // Detecting overflow - let last = $n_words - word_shift - if bit_shift > 0 { 1 } else { 0 }; - let overflow = if bit_shift > 0 { - (original[last] >> (64 - bit_shift)) > 0 - } else if word_shift > 0 { - original[last] > 0 - } else { - false - }; - - for i in last+1..$n_words-1 { - if original[i] > 0 { - return ($name(ret), true); - } - } - ($name(ret), overflow) - } - } - - impl $name { - /// Multiplication by u32 - fn mul_u32(self, other: u32) -> Self { - let $name(ref arr) = self; - let mut carry = [0u64; $n_words]; - let mut ret = [0u64; $n_words]; - for i in 0..$n_words { - let upper = other as u64 * (arr[i] >> 32); - let lower = other as u64 * (arr[i] & 0xFFFFFFFF); - - ret[i] = lower.wrapping_add(upper << 32); - - if i < $n_words - 1 { - carry[i + 1] = upper >> 32; - if ret[i] < lower { - carry[i + 1] += 1; - } - } - } - $name(ret) + $name(carry) - } - - /// Overflowing multiplication by u32 - fn overflowing_mul_u32(self, other: u32) -> (Self, bool) { - let $name(ref arr) = self; - let mut carry = [0u64; $n_words]; - let mut ret = [0u64; $n_words]; - let mut overflow = false; - for i in 0..$n_words { - let upper = other as u64 * (arr[i] >> 32); - let lower = other as u64 * (arr[i] & 0xFFFFFFFF); - - ret[i] = lower.wrapping_add(upper << 32); - - if i < $n_words - 1 { - carry[i + 1] = upper >> 32; - if ret[i] < lower { - carry[i + 1] += 1; - } - } else if (upper >> 32) > 0 || ret[i] < lower { - overflow = true - } - } - let result = overflowing!( - $name(ret).overflowing_add($name(carry)), - overflow - ); - (result, overflow) - } - } - - impl Default for $name { - fn default() -> Self { - $name::zero() - } - } - - impl serde::Serialize for $name { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> - where S: serde::Serializer { - let mut hex = "0x".to_owned(); - let mut bytes = [0u8; 8 * $n_words]; - self.to_bytes(&mut bytes); - let len = cmp::max((self.bits() + 7) / 8, 1); - hex.push_str(bytes[bytes.len() - len..].to_hex().as_ref()); - serializer.visit_str(hex.as_ref()) - } - } - - impl From for $name { - fn from(value: u64) -> $name { - let mut ret = [0; $n_words]; - ret[0] = value; - $name(ret) - } - } - - impl FromJson for $name { - fn from_json(json: &Json) -> Self { - match *json { - Json::String(ref s) => { - if s.len() >= 2 && &s[0..2] == "0x" { - FromStr::from_str(&s[2..]).unwrap_or_else(|_| Default::default()) - } else { - Uint::from_dec_str(s).unwrap_or_else(|_| Default::default()) - } - }, - Json::U64(u) => From::from(u), - Json::I64(i) => From::from(i as u64), - _ => Uint::zero(), - } - } - } - - impl_map_from!($name, u8, u64); - impl_map_from!($name, u16, u64); - impl_map_from!($name, u32, u64); - impl_map_from!($name, usize, u64); - - impl From for $name { - fn from(value: i64) -> $name { - match value >= 0 { - true => From::from(value as u64), - false => { panic!("Unsigned integer can't be created from negative value"); } - } - } - } - - impl_map_from!($name, i8, i64); - impl_map_from!($name, i16, i64); - impl_map_from!($name, i32, i64); - impl_map_from!($name, isize, i64); - - impl<'a> From<&'a [u8]> for $name { - fn from(bytes: &[u8]) -> $name { - assert!($n_words * 8 >= bytes.len()); - - let mut ret = [0; $n_words]; - for i in 0..bytes.len() { - let rev = bytes.len() - 1 - i; - let pos = rev / 8; - ret[pos] += (bytes[i] as u64) << ((rev % 8) * 8); - } - $name(ret) - } - } - - impl FromStr for $name { - type Err = FromHexError; - - fn from_str(value: &str) -> Result<$name, Self::Err> { - let bytes: Vec = match value.len() % 2 == 0 { - true => try!(value.from_hex()), - false => try!(("0".to_owned() + value).from_hex()) - }; - - let bytes_ref: &[u8] = &bytes; - Ok(From::from(bytes_ref)) - } - } - - impl Add<$name> for $name { - type Output = $name; - - fn add(self, other: $name) -> $name { - let $name(ref me) = self; - let $name(ref you) = other; - let mut ret = [0u64; $n_words]; - let mut carry = [0u64; $n_words]; - let mut b_carry = false; - for i in 0..$n_words { - if i < $n_words - 1 { - ret[i] = me[i].wrapping_add(you[i]); - if ret[i] < me[i] { - carry[i + 1] = 1; - b_carry = true; - } - } else { - ret[i] = me[i] + you[i]; - } - } - if b_carry { $name(ret) + $name(carry) } else { $name(ret) } - } - } - - impl Sub<$name> for $name { - type Output = $name; - - #[inline] - fn sub(self, other: $name) -> $name { - panic_on_overflow!(self < other); - let res = overflowing!((!other).overflowing_add(From::from(1u64))); - overflowing!(self.overflowing_add(res)) - } - } - - impl Mul<$name> for $name { - type Output = $name; - - fn mul(self, other: $name) -> $name { - let mut res = $name::from(0u64); - // TODO: be more efficient about this - for i in 0..(2 * $n_words) { - let v = self.mul_u32((other >> (32 * i)).low_u32()); - let (r, overflow) = v.overflowing_shl(32 * i as u32); - panic_on_overflow!(overflow); - res = res + r; - } - res - } - } - - impl Div<$name> for $name { - type Output = $name; - - fn div(self, other: $name) -> $name { - let mut sub_copy = self; - let mut shift_copy = other; - let mut ret = [0u64; $n_words]; - - let my_bits = self.bits(); - let your_bits = other.bits(); - - // Check for division by 0 - assert!(your_bits != 0); - - // Early return in case we are dividing by a larger number than us - if my_bits < your_bits { - return $name(ret); - } - - // Bitwise long division - let mut shift = my_bits - your_bits; - shift_copy = shift_copy << shift; - loop { - if sub_copy >= shift_copy { - ret[shift / 64] |= 1 << (shift % 64); - sub_copy = overflowing!(sub_copy.overflowing_sub(shift_copy)); - } - shift_copy = shift_copy >> 1; - if shift == 0 { break; } - shift -= 1; - } - - $name(ret) - } - } - - impl Rem<$name> for $name { - type Output = $name; - - fn rem(self, other: $name) -> $name { - let times = self / other; - self - (times * other) - } - } - - // TODO: optimise and traitify. - - impl<'a> AddAssign<&'a $name> for $name { - fn add_assign(&mut self, other: &'a Self) { - *self = self.add(*other); - } - } - - impl<'a> SubAssign<&'a $name> for $name { - fn sub_assign(&mut self, other: &'a Self) { - *self = self.sub(*other); - } - } - - impl<'a> MulAssign<&'a $name> for $name { - fn mul_assign(&mut self, other: &'a Self) { - *self = self.mul(*other); - } - } - - impl<'a> DivAssign<&'a $name> for $name { - fn div_assign(&mut self, other: &'a Self) { - *self = self.div(*other); - } - } - - impl<'a> RemAssign<&'a $name> for $name { - fn rem_assign(&mut self, other: &'a Self) { - *self = self.rem(*other); - } - } - - impl AddAssign<$name> for $name { - fn add_assign(&mut self, other: Self) { - *self = self.add(other); - } - } - - impl SubAssign<$name> for $name { - fn sub_assign(&mut self, other: Self) { - *self = self.sub(other); - } - } - - impl MulAssign<$name> for $name { - fn mul_assign(&mut self, other: Self) { - *self = self.mul(other); - } - } - - impl DivAssign<$name> for $name { - fn div_assign(&mut self, other: Self) { - *self = self.div(other); - } - } - - impl RemAssign<$name> for $name { - fn rem_assign(&mut self, other: Self) { - *self = self.rem(other); - } - } - - impl BitAnd<$name> for $name { - type Output = $name; - - #[inline] - fn bitand(self, other: $name) -> $name { - let $name(ref arr1) = self; - let $name(ref arr2) = other; - let mut ret = [0u64; $n_words]; - for i in 0..$n_words { - ret[i] = arr1[i] & arr2[i]; - } - $name(ret) - } - } - - impl BitXor<$name> for $name { - type Output = $name; - - #[inline] - fn bitxor(self, other: $name) -> $name { - let $name(ref arr1) = self; - let $name(ref arr2) = other; - let mut ret = [0u64; $n_words]; - for i in 0..$n_words { - ret[i] = arr1[i] ^ arr2[i]; - } - $name(ret) - } - } - - impl BitOr<$name> for $name { - type Output = $name; - - #[inline] - fn bitor(self, other: $name) -> $name { - let $name(ref arr1) = self; - let $name(ref arr2) = other; - let mut ret = [0u64; $n_words]; - for i in 0..$n_words { - ret[i] = arr1[i] | arr2[i]; - } - $name(ret) - } - } - - impl Not for $name { - type Output = $name; - - #[inline] - fn not(self) -> $name { - let $name(ref arr) = self; - let mut ret = [0u64; $n_words]; - for i in 0..$n_words { - ret[i] = !arr[i]; - } - $name(ret) - } - } - - impl Shl for $name { - type Output = $name; - - fn shl(self, shift: usize) -> $name { - let $name(ref original) = self; - let mut ret = [0u64; $n_words]; - let word_shift = shift / 64; - let bit_shift = shift % 64; - for i in 0..$n_words { - // Shift - if i + word_shift < $n_words { - ret[i + word_shift] += original[i] << bit_shift; - } - // Carry - if bit_shift > 0 && i + word_shift + 1 < $n_words { - ret[i + word_shift + 1] += original[i] >> (64 - bit_shift); - } - } - $name(ret) - } - } - - impl Shr for $name { - type Output = $name; - - fn shr(self, shift: usize) -> $name { - let $name(ref original) = self; - let mut ret = [0u64; $n_words]; - let word_shift = shift / 64; - let bit_shift = shift % 64; - for i in word_shift..$n_words { - // Shift - ret[i - word_shift] += original[i] >> bit_shift; - // Carry - if bit_shift > 0 && i < $n_words - 1 { - ret[i - word_shift] += original[i + 1] << (64 - bit_shift); - } - } - $name(ret) - } - } - - impl Ord for $name { - fn cmp(&self, other: &$name) -> Ordering { - let &$name(ref me) = self; - let &$name(ref you) = other; - for i in 0..$n_words { - if me[$n_words - 1 - i] < you[$n_words - 1 - i] { return Ordering::Less; } - if me[$n_words - 1 - i] > you[$n_words - 1 - i] { return Ordering::Greater; } - } - Ordering::Equal - } - } - - impl PartialOrd for $name { - fn partial_cmp(&self, other: &$name) -> Option { - Some(self.cmp(other)) - } - } - - impl fmt::Debug for $name { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self, f) - } - } - - impl fmt::Display for $name { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if *self == $name::zero() { - return write!(f, "0"); - } - - let mut s = String::new(); - let mut current = *self; - let ten = $name::from(10); - - while current != $name::zero() { - s = format!("{}{}", (current % ten).low_u32(), s); - current = current / ten; - } - - write!(f, "{}", s) - } - } - - impl fmt::LowerHex for $name { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let &$name(ref data) = self; - try!(write!(f, "0x")); - let mut latch = false; - for ch in data.iter().rev() { - for x in 0..16 { - let nibble = (ch & (15u64 << ((15 - x) * 4) as u64)) >> (((15 - x) * 4) as u64); - if !latch { latch = nibble != 0 } - if latch { - try!(write!(f, "{:x}", nibble)); - } - } - } - Ok(()) - } - } - - impl Hash for $name { - fn hash(&self, state: &mut H) where H: Hasher { - unsafe { state.write(::std::slice::from_raw_parts(self.0.as_ptr() as *mut u8, self.0.len() * 8)); } - state.finish(); - } - } - ); -} - -construct_uint!(U512, 8); -construct_uint!(U256, 4); -construct_uint!(U128, 2); - -impl From for U512 { - fn from(value: U256) -> U512 { - let U256(ref arr) = value; - let mut ret = [0; 8]; - ret[0] = arr[0]; - ret[1] = arr[1]; - ret[2] = arr[2]; - ret[3] = arr[3]; - U512(ret) - } -} - -impl From for U256 { - fn from(value: U512) -> U256 { - let U512(ref arr) = value; - if arr[4] | arr[5] | arr[6] | arr[7] != 0 { - panic!("Overflow"); - } - let mut ret = [0; 4]; - ret[0] = arr[0]; - ret[1] = arr[1]; - ret[2] = arr[2]; - ret[3] = arr[3]; - U256(ret) - } -} - -impl From for U128 { - fn from(value: U256) -> U128 { - let U256(ref arr) = value; - if arr[2] | arr[3] != 0 { - panic!("Overflow"); - } - let mut ret = [0; 2]; - ret[0] = arr[0]; - ret[1] = arr[1]; - U128(ret) - } -} - -impl From for U128 { - fn from(value: U512) -> U128 { - let U512(ref arr) = value; - if arr[2] | arr[3] | arr[4] | arr[5] | arr[6] | arr[7] != 0 { - panic!("Overflow"); - } - let mut ret = [0; 2]; - ret[0] = arr[0]; - ret[1] = arr[1]; - U128(ret) - } -} - -impl From for U512 { - fn from(value: U128) -> U512 { - let U128(ref arr) = value; - let mut ret = [0; 8]; - ret[0] = arr[0]; - ret[1] = arr[1]; - U512(ret) - } -} - -impl From for U256 { - fn from(value: U128) -> U256 { - let U128(ref arr) = value; - let mut ret = [0; 4]; - ret[0] = arr[0]; - ret[1] = arr[1]; - U256(ret) - } -} - -impl From for u64 { - fn from(value: U256) -> u64 { - value.as_u64() - } -} - -impl From for u32 { - fn from(value: U256) -> u32 { - value.as_u32() - } -} - -/// Constant value of `U256::zero()` that can be used for a reference saving an additional instance creation. -pub const ZERO_U256: U256 = U256([0x00u64; 4]); -/// Constant value of `U256::one()` that can be used for a reference saving an additional instance creation. -pub const ONE_U256: U256 = U256([0x01u64, 0x00u64, 0x00u64, 0x00u64]); - -#[cfg(test)] -mod tests { - use uint::{Uint, U128, U256, U512}; - use std::str::FromStr; - - #[test] - pub fn assign_ops() { - let x: U256 = x!(69); - let y: U256 = x!(42); - { - let mut z = x; - z += y; - assert_eq!(z, x + y); - } - { - let mut z = x; - z -= y; - assert_eq!(z, x - y); - } - { - let mut z = x; - z *= y; - assert_eq!(z, x * y); - } - { - let mut z = x; - z /= y; - assert_eq!(z, x / y); - } - { - let mut z = x; - z %= y; - assert_eq!(z, x % y); - } - } - - #[test] - pub fn uint256_from() { - let e = U256([10, 0, 0, 0]); - - // test unsigned initialization - let ua = U256::from(10u8); - let ub = U256::from(10u16); - let uc = U256::from(10u32); - let ud = U256::from(10u64); - assert_eq!(e, ua); - assert_eq!(e, ub); - assert_eq!(e, uc); - assert_eq!(e, ud); - - // test initialization from bytes - let va = U256::from(&[10u8][..]); - assert_eq!(e, va); - - // more tests for initialization from bytes - assert_eq!(U256([0x1010, 0, 0, 0]), U256::from(&[0x10u8, 0x10][..])); - assert_eq!(U256([0x12f0, 0, 0, 0]), U256::from(&[0x12u8, 0xf0][..])); - assert_eq!(U256([0x12f0, 0, 0, 0]), U256::from(&[0, 0x12u8, 0xf0][..])); - assert_eq!(U256([0x12f0, 0 , 0, 0]), U256::from(&[0, 0, 0, 0, 0, 0, 0, 0x12u8, 0xf0][..])); - assert_eq!(U256([0x12f0, 1 , 0, 0]), U256::from(&[1, 0, 0, 0, 0, 0, 0, 0x12u8, 0xf0][..])); - assert_eq!(U256([0x12f0, 1 , 0x0910203040506077, 0x8090a0b0c0d0e0f0]), U256::from(&[ - 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, - 0x09, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x77, - 0, 0, 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, 0x12u8, 0xf0][..])); - assert_eq!(U256([0x00192437100019fa, 0x243710, 0, 0]), U256::from(&[ - 0x24u8, 0x37, 0x10, - 0, 0x19, 0x24, 0x37, 0x10, 0, 0x19, 0xfa][..])); - - // test initializtion from string - let sa = U256::from_str("0a").unwrap(); - assert_eq!(e, sa); - assert_eq!(U256([0x1010, 0, 0, 0]), U256::from_str("1010").unwrap()); - assert_eq!(U256([0x12f0, 0, 0, 0]), U256::from_str("12f0").unwrap()); - assert_eq!(U256([0x12f0, 0, 0, 0]), U256::from_str("12f0").unwrap()); - assert_eq!(U256([0x12f0, 0 , 0, 0]), U256::from_str("0000000012f0").unwrap()); - assert_eq!(U256([0x12f0, 1 , 0, 0]), U256::from_str("0100000000000012f0").unwrap()); - assert_eq!(U256([0x12f0, 1 , 0x0910203040506077, 0x8090a0b0c0d0e0f0]), U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0").unwrap()); - } - - #[test] - pub fn uint256_to() { - let hex = "8090a0b0c0d0e0f00910203040506077583a2cf8264910e1436bda32571012f0"; - let uint = U256::from_str(hex).unwrap(); - let mut bytes = [0u8; 32]; - uint.to_bytes(&mut bytes); - let uint2 = U256::from(&bytes[..]); - assert_eq!(uint, uint2); - } - - #[test] - pub fn uint256_bits_test() { - assert_eq!(U256::from(0u64).bits(), 0); - assert_eq!(U256::from(255u64).bits(), 8); - assert_eq!(U256::from(256u64).bits(), 9); - assert_eq!(U256::from(300u64).bits(), 9); - assert_eq!(U256::from(60000u64).bits(), 16); - assert_eq!(U256::from(70000u64).bits(), 17); - - //// Try to read the following lines out loud quickly - let mut shl = U256::from(70000u64); - shl = shl << 100; - assert_eq!(shl.bits(), 117); - shl = shl << 100; - assert_eq!(shl.bits(), 217); - shl = shl << 100; - assert_eq!(shl.bits(), 0); - - //// Bit set check - //// 01010 - assert!(!U256::from(10u8).bit(0)); - assert!(U256::from(10u8).bit(1)); - assert!(!U256::from(10u8).bit(2)); - assert!(U256::from(10u8).bit(3)); - assert!(!U256::from(10u8).bit(4)); - - //// byte check - assert_eq!(U256::from(10u8).byte(0), 10); - assert_eq!(U256::from(0xffu64).byte(0), 0xff); - assert_eq!(U256::from(0xffu64).byte(1), 0); - assert_eq!(U256::from(0x01ffu64).byte(0), 0xff); - assert_eq!(U256::from(0x01ffu64).byte(1), 0x1); - assert_eq!(U256([0u64, 0xfc, 0, 0]).byte(8), 0xfc); - assert_eq!(U256([0u64, 0, 0, u64::max_value()]).byte(31), 0xff); - assert_eq!(U256([0u64, 0, 0, (u64::max_value() >> 8) + 1]).byte(31), 0x01); - } - - #[test] - #[allow(eq_op)] - pub fn uint256_comp_test() { - let small = U256([10u64, 0, 0, 0]); - let big = U256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0]); - let bigger = U256([0x9C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0]); - let biggest = U256([0x5C8C3EE70C644118u64, 0x0209E7378231E632, 0, 1]); - - assert!(small < big); - assert!(big < bigger); - assert!(bigger < biggest); - assert!(bigger <= biggest); - assert!(biggest <= biggest); - assert!(bigger >= big); - assert!(bigger >= small); - assert!(small <= small); - } - - #[test] - pub fn uint256_arithmetic_test() { - let init = U256::from(0xDEADBEEFDEADBEEFu64); - let copy = init; - - let add = init + copy; - assert_eq!(add, U256([0xBD5B7DDFBD5B7DDEu64, 1, 0, 0])); - // Bitshifts - let shl = add << 88; - assert_eq!(shl, U256([0u64, 0xDFBD5B7DDE000000, 0x1BD5B7D, 0])); - let shr = shl >> 40; - assert_eq!(shr, U256([0x7DDE000000000000u64, 0x0001BD5B7DDFBD5B, 0, 0])); - // Increment - let incr = shr + U256::from(1u64); - assert_eq!(incr, U256([0x7DDE000000000001u64, 0x0001BD5B7DDFBD5B, 0, 0])); - // Subtraction - let sub = overflowing!(incr.overflowing_sub(init)); - assert_eq!(sub, U256([0x9F30411021524112u64, 0x0001BD5B7DDFBD5A, 0, 0])); - // Multiplication - let mult = sub.mul_u32(300); - assert_eq!(mult, U256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0])); - // Division - assert_eq!(U256::from(105u8) / U256::from(5u8), U256::from(21u8)); - let div = mult / U256::from(300u16); - assert_eq!(div, U256([0x9F30411021524112u64, 0x0001BD5B7DDFBD5A, 0, 0])); - // TODO: bit inversion - } - - #[test] - pub fn uint256_extreme_bitshift_test() { - //// Shifting a u64 by 64 bits gives an undefined value, so make sure that - //// we're doing the Right Thing here - let init = U256::from(0xDEADBEEFDEADBEEFu64); - - assert_eq!(init << 64, U256([0, 0xDEADBEEFDEADBEEF, 0, 0])); - let add = (init << 64) + init; - assert_eq!(add, U256([0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0, 0])); - assert_eq!(add >> 0, U256([0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0, 0])); - assert_eq!(add << 0, U256([0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0, 0])); - assert_eq!(add >> 64, U256([0xDEADBEEFDEADBEEF, 0, 0, 0])); - assert_eq!(add << 64, U256([0, 0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0])); - } - - #[test] - pub fn uint256_exp10() { - assert_eq!(U256::exp10(0), U256::from(1u64)); - println!("\none: {:?}", U256::from(1u64)); - println!("ten: {:?}", U256::from(10u64)); - assert_eq!(U256::from(2u64) * U256::from(10u64), U256::from(20u64)); - assert_eq!(U256::exp10(1), U256::from(10u64)); - assert_eq!(U256::exp10(2), U256::from(100u64)); - assert_eq!(U256::exp10(5), U256::from(100000u64)); - } - - #[test] - pub fn uint256_mul32() { - assert_eq!(U256::from(0u64).mul_u32(2), U256::from(0u64)); - assert_eq!(U256::from(1u64).mul_u32(2), U256::from(2u64)); - assert_eq!(U256::from(10u64).mul_u32(2), U256::from(20u64)); - assert_eq!(U256::from(10u64).mul_u32(5), U256::from(50u64)); - assert_eq!(U256::from(1000u64).mul_u32(50), U256::from(50000u64)); - } - - #[test] - fn uint256_pow () { - assert_eq!(U256::from(10).pow(U256::from(0)), U256::from(1)); - assert_eq!(U256::from(10).pow(U256::from(1)), U256::from(10)); - assert_eq!(U256::from(10).pow(U256::from(2)), U256::from(100)); - assert_eq!(U256::from(10).pow(U256::from(3)), U256::from(1000)); - assert_eq!(U256::from(10).pow(U256::from(20)), U256::exp10(20)); - } - - #[test] - #[should_panic] - fn uint256_pow_overflow_panic () { - U256::from(2).pow(U256::from(0x100)); - } - - #[test] - fn uint256_overflowing_pow () { - // assert_eq!( - // U256::from(2).overflowing_pow(U256::from(0xff)), - // (U256::from_str("8000000000000000000000000000000000000000000000000000000000000000").unwrap(), false) - // ); - assert_eq!( - U256::from(2).overflowing_pow(U256::from(0x100)), - (U256::zero(), true) - ); - } - - #[test] - pub fn uint256_mul1() { - assert_eq!(U256::from(1u64) * U256::from(10u64), U256::from(10u64)); - } - - #[test] - pub fn uint256_overflowing_mul() { - assert_eq!( - U256::from_str("100000000000000000000000000000000").unwrap().overflowing_mul( - U256::from_str("100000000000000000000000000000000").unwrap() - ), - (U256::zero(), true) - ); - } - - #[test] - pub fn uint128_add() { - assert_eq!( - U128::from_str("fffffffffffffffff").unwrap() + U128::from_str("fffffffffffffffff").unwrap(), - U128::from_str("1ffffffffffffffffe").unwrap() - ); - } - - #[test] - pub fn uint128_add_overflow() { - assert_eq!( - U128::from_str("ffffffffffffffffffffffffffffffff").unwrap() - .overflowing_add( - U128::from_str("ffffffffffffffffffffffffffffffff").unwrap() - ), - (U128::from_str("fffffffffffffffffffffffffffffffe").unwrap(), true) - ); - } - - #[test] - #[should_panic] - // overflows panic only in debug builds. Running this test with `--release` flag, always fails - #[ignore] - pub fn uint128_add_overflow_panic() { - U128::from_str("ffffffffffffffffffffffffffffffff").unwrap() - + - U128::from_str("ffffffffffffffffffffffffffffffff").unwrap(); - } - - #[test] - pub fn uint128_mul() { - assert_eq!( - U128::from_str("fffffffff").unwrap() * U128::from_str("fffffffff").unwrap(), - U128::from_str("ffffffffe000000001").unwrap()); - } - - #[test] - pub fn uint512_mul() { - assert_eq!( - U512::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() - * - U512::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(), - U512::from_str("3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000001").unwrap() - ); - } - - #[test] - pub fn uint256_mul_overflow() { - assert_eq!( - U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() - .overflowing_mul( - U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() - ), - (U256::from_str("1").unwrap(), true) - ); - } - - - - #[test] - #[should_panic] - pub fn uint256_mul_overflow_panic() { - U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() - * - U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(); - } - - #[test] - pub fn uint256_sub_overflow() { - assert_eq!( - U256::from_str("0").unwrap() - .overflowing_sub( - U256::from_str("1").unwrap() - ), - (U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(), true) - ); - } - - #[test] - #[should_panic] - pub fn uint256_sub_overflow_panic() { - U256::from_str("0").unwrap() - - - U256::from_str("1").unwrap(); - } - - #[test] - pub fn uint256_shl_overflow() { - assert_eq!( - U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() - .overflowing_shl(4), - (U256::from_str("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0").unwrap(), true) - ); - } - - #[test] - pub fn uint256_shl_overflow_words() { - assert_eq!( - U256::from_str("0000000000000001ffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() - .overflowing_shl(64), - (U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000").unwrap(), true) - ); - assert_eq!( - U256::from_str("0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() - .overflowing_shl(64), - (U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000").unwrap(), false) - ); - } - - #[test] - pub fn uint256_shl_overflow_words2() { - assert_eq!( - U256::from_str("00000000000000000000000000000001ffffffffffffffffffffffffffffffff").unwrap() - .overflowing_shl(128), - (U256::from_str("ffffffffffffffffffffffffffffffff00000000000000000000000000000000").unwrap(), true) - ); - assert_eq!( - U256::from_str("00000000000000000000000000000000ffffffffffffffffffffffffffffffff").unwrap() - .overflowing_shl(128), - (U256::from_str("ffffffffffffffffffffffffffffffff00000000000000000000000000000000").unwrap(), false) - ); - assert_eq!( - U256::from_str("00000000000000000000000000000000ffffffffffffffffffffffffffffffff").unwrap() - .overflowing_shl(129), - (U256::from_str("fffffffffffffffffffffffffffffffe00000000000000000000000000000000").unwrap(), true) - ); - } - - - #[test] - pub fn uint256_shl_overflow2() { - assert_eq!( - U256::from_str("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() - .overflowing_shl(4), - (U256::from_str("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0").unwrap(), false) - ); - } - - #[test] - pub fn uint256_mul() { - assert_eq!( - U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() - * - U256::from_str("2").unwrap(), - U256::from_str("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe").unwrap() - ); - } - - #[test] - fn uint256_div() { - assert_eq!(U256::from(10u64) / U256::from(1u64), U256::from(10u64)); - assert_eq!(U256::from(10u64) / U256::from(2u64), U256::from(5u64)); - assert_eq!(U256::from(10u64) / U256::from(3u64), U256::from(3u64)); - } - - #[test] - fn uint256_rem() { - assert_eq!(U256::from(10u64) % U256::from(1u64), U256::from(0u64)); - assert_eq!(U256::from(10u64) % U256::from(3u64), U256::from(1u64)); - } - - #[test] - fn uint256_from_dec_str() { - assert_eq!(U256::from_dec_str("10").unwrap(), U256::from(10u64)); - assert_eq!(U256::from_dec_str("1024").unwrap(), U256::from(1024u64)); - } - - #[test] - fn display_uint() { - let s = "12345678987654321023456789"; - assert_eq!(format!("{}", U256::from_dec_str(s).unwrap()), s); - } - - #[test] - fn display_uint_zero() { - assert_eq!(format!("{}", U256::from(0)), "0"); - } -} -